Compare commits
No commits in common. "9b798f5fe42536aae2e1bdf8658ce53a62f5321f" and "09064cc028674c07c07319db5c6b9cd6c576da7d" have entirely different histories.
9b798f5fe4
...
09064cc028
1
.gitignore
vendored
@ -7,7 +7,6 @@ yarn-error.log*
|
|||||||
# База данных (можно исключить если не хотите хранить в репозитории)
|
# База данных (можно исключить если не хотите хранить в репозитории)
|
||||||
notes.db
|
notes.db
|
||||||
*.db
|
*.db
|
||||||
database/
|
|
||||||
|
|
||||||
# Переменные окружения
|
# Переменные окружения
|
||||||
.env
|
.env
|
||||||
|
|||||||
95
CALENDAR_FEATURE.md
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
# Функция календаря в NoteJS
|
||||||
|
|
||||||
|
## Описание
|
||||||
|
|
||||||
|
Добавлена новая функция интерактивного календаря на странице заметок. Календарь расположен слева от формы создания заметок и обеспечивает удобную навигацию по датам.
|
||||||
|
|
||||||
|
## Что было добавлено
|
||||||
|
|
||||||
|
### 1. HTML разметка (`public/notes.html`)
|
||||||
|
- Новый контейнер `main-wrapper` для двухколонного макета
|
||||||
|
- Боковая панель `calendar-sidebar` с календарём
|
||||||
|
- Элементы для отображения дней месяца, навигации между месяцами
|
||||||
|
- Дни недели на русском языке (Пн, Вт, Ср, Чт, Пт, Сб, Вс)
|
||||||
|
|
||||||
|
### 2. Стили CSS (`public/style.css`)
|
||||||
|
- Стили для двухколонного макета с использованием flexbox
|
||||||
|
- Красивое оформление календаря:
|
||||||
|
- Сегодняшний день: синий цвет (класс `today`)
|
||||||
|
- Выбранный день: зелёный цвет (класс `selected`)
|
||||||
|
- Дни соседних месяцев: серый цвет (класс `other-month`)
|
||||||
|
- Активные дни имеют эффекты наведения (hover)
|
||||||
|
- Адаптивный дизайн для мобильных устройств (при ширине < 768px календарь переходит на всю ширину)
|
||||||
|
|
||||||
|
### 3. JavaScript функциональность (`public/calendar.js`)
|
||||||
|
Новый файл `calendar.js` содержит класс `Calendar` с методами:
|
||||||
|
- `init()` - инициализация календаря
|
||||||
|
- `render()` - отрисовка календаря
|
||||||
|
- `renderTitle()` - отрисовка названия месяца и года
|
||||||
|
- `renderDays()` - отрисовка дней месяца
|
||||||
|
- `previousMonth()` - переход на предыдущий месяц
|
||||||
|
- `nextMonth()` - переход на следующий месяц
|
||||||
|
- `selectDate()` - выбор даты при клике
|
||||||
|
- `isToday()` - проверка, является ли день сегодняшним
|
||||||
|
- `isSelected()` - проверка, выбран ли день
|
||||||
|
- `formatDate()` - форматирование даты в формате ДД.МММ.ГГГГ
|
||||||
|
|
||||||
|
## Особенности
|
||||||
|
|
||||||
|
✅ **Интерактивные кнопки навигации** - легко переходить между месяцами
|
||||||
|
✅ **Выделение сегодняшнего дня** - синий фон на текущую дату
|
||||||
|
✅ **Выделение выбранной даты** - зелёный фон на выбранную дату
|
||||||
|
✅ **Русские названия** - месяцы и дни недели на русском языке
|
||||||
|
✅ **Адаптивный дизайн** - правильно отображается на мобильных устройствах
|
||||||
|
✅ **Без зависимостей** - не требует дополнительных библиотек
|
||||||
|
✅ **Чистый код** - использует современный JavaScript с классами
|
||||||
|
|
||||||
|
## Макет
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────┐
|
||||||
|
│ Заголовок (логин, выход) │
|
||||||
|
├──────────────┬──────────────────────────────────┤
|
||||||
|
│ Календарь │ Форма создания заметки │
|
||||||
|
│ │ │
|
||||||
|
│ < Октябрь > │ Кнопки форматирования (B I H) │
|
||||||
|
│ Пн Вт Ср... │ [Текстовое поле] │
|
||||||
|
│ 1 2 3... │ [Сохранить] │
|
||||||
|
│ │ │
|
||||||
|
├──────────────┴──────────────────────────────────┤
|
||||||
|
│ Список заметок │
|
||||||
|
│ [Заметка 1] │
|
||||||
|
│ [Заметка 2] │
|
||||||
|
│ [Заметка 3] │
|
||||||
|
└─────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Использование
|
||||||
|
|
||||||
|
1. Откройте страницу заметок (`/notes`)
|
||||||
|
2. Слева вы увидите календарь текущего месяца
|
||||||
|
3. Нажимайте кнопки `<` и `>` для навигации по месяцам
|
||||||
|
4. Нажимайте на любой день для выбора
|
||||||
|
5. Выбранный день будет выделен зелёным цветом
|
||||||
|
|
||||||
|
## Возможные расширения
|
||||||
|
|
||||||
|
- Фильтрация заметок по выбранной дате
|
||||||
|
- Отображение точек/маркеров на днях, в которые созданы заметки
|
||||||
|
- Всплывающие подсказки с предпросмотром заметок при наведении
|
||||||
|
- Возможность создания заметки на конкретную дату
|
||||||
|
- Синхронизация выбранной даты в календаре с фильтром заметок
|
||||||
|
|
||||||
|
## Тестирование
|
||||||
|
|
||||||
|
✅ Навигация между месяцами работает корректно
|
||||||
|
✅ Выделение текущего дня работает
|
||||||
|
✅ Выделение выбранного дня работает
|
||||||
|
✅ Адаптивный дизайн для мобильных устройств работает
|
||||||
|
✅ Нет ошибок в консоли браузера
|
||||||
|
✅ Стили правильно загружаются
|
||||||
|
|
||||||
|
## Версия
|
||||||
|
|
||||||
|
- Дата добавления: октябрь 2025
|
||||||
|
- Совместимость: все современные браузеры
|
||||||
115
DEPLOYMENT.md
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
# Инструкции по развертыванию изменений
|
||||||
|
|
||||||
|
## Обзор изменений
|
||||||
|
|
||||||
|
В этом коммите добавлены следующие функции:
|
||||||
|
|
||||||
|
### ✅ Новые возможности:
|
||||||
|
|
||||||
|
- **Личный кабинет** с возможностью загрузки аватарки
|
||||||
|
- **Управление аватарками**: загрузка, удаление, предварительный просмотр
|
||||||
|
- **Исправлено отображение аватарки** на странице профиля (центрирование)
|
||||||
|
- **Убрано отображение аватарки** со страницы заметок для чистоты интерфейса
|
||||||
|
- **Обновлен .gitignore** с исключениями для загруженных файлов и временных файлов
|
||||||
|
- **Обновлен README.md** с документацией по новым функциям
|
||||||
|
|
||||||
|
### 🔧 Технические улучшения:
|
||||||
|
|
||||||
|
- Добавлена валидация загружаемых файлов (тип, размер, формат)
|
||||||
|
- Улучшена безопасность с изоляцией пользовательских данных
|
||||||
|
- Обновлены CSS стили для правильного отображения аватарки
|
||||||
|
|
||||||
|
## Файлы для применения изменений
|
||||||
|
|
||||||
|
### 1. Патч файлы:
|
||||||
|
|
||||||
|
- `0001-feat.patch` - Первый коммит с функциями тегов
|
||||||
|
- `0002-feat.patch` - Второй коммит с личным кабинетом и аватарками
|
||||||
|
|
||||||
|
### 2. Архив:
|
||||||
|
|
||||||
|
- `NoteJS-changes.tar.gz` - Полный архив с изменениями
|
||||||
|
|
||||||
|
### 3. Скрипт:
|
||||||
|
|
||||||
|
- `apply-changes.sh` - Скрипт для автоматического применения изменений
|
||||||
|
|
||||||
|
## Способы применения изменений
|
||||||
|
|
||||||
|
### Способ 1: Использование патч файлов
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Применить патчи
|
||||||
|
git apply 0001-feat.patch
|
||||||
|
git apply 0002-feat.patch
|
||||||
|
|
||||||
|
# Добавить изменения в индекс
|
||||||
|
git add .
|
||||||
|
|
||||||
|
# Сделать коммит
|
||||||
|
git commit -m "feat: добавлен личный кабинет с аватарками и улучшена навигация"
|
||||||
|
|
||||||
|
# Отправить в удаленный репозиторий
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
### Способ 2: Использование скрипта
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Запустить скрипт
|
||||||
|
./apply-changes.sh
|
||||||
|
|
||||||
|
# Затем следовать инструкциям скрипта
|
||||||
|
```
|
||||||
|
|
||||||
|
### Способ 3: Ручное применение
|
||||||
|
|
||||||
|
1. Скопировать измененные файлы из архива `NoteJS-changes.tar.gz`
|
||||||
|
2. Заменить соответствующие файлы в проекте
|
||||||
|
3. Выполнить `git add .` и `git commit`
|
||||||
|
|
||||||
|
## Структура изменений
|
||||||
|
|
||||||
|
### Измененные файлы:
|
||||||
|
|
||||||
|
- `public/app.js` - Убрано отображение аватарки со страницы заметок
|
||||||
|
- `public/style.css` - Исправлено центрирование аватарки
|
||||||
|
- `public/profile.html` - Страница личного кабинета
|
||||||
|
- `public/profile.js` - Логика личного кабинета
|
||||||
|
- `server.js` - API для управления аватарками
|
||||||
|
- `.gitignore` - Обновлены исключения
|
||||||
|
- `README.md` - Обновлена документация
|
||||||
|
|
||||||
|
### Новые файлы:
|
||||||
|
|
||||||
|
- `public/uploads/` - Директория для загруженных аватарок
|
||||||
|
- `DEPLOYMENT.md` - Этот файл с инструкциями
|
||||||
|
|
||||||
|
## Проверка после применения
|
||||||
|
|
||||||
|
После применения изменений убедитесь, что:
|
||||||
|
|
||||||
|
1. ✅ Сервер запускается без ошибок
|
||||||
|
2. ✅ Страница профиля отображается корректно
|
||||||
|
3. ✅ Аватарка загружается и отображается правильно
|
||||||
|
4. ✅ Аватарка не отображается на странице заметок
|
||||||
|
5. ✅ Все функции работают как ожидается
|
||||||
|
|
||||||
|
## Откат изменений
|
||||||
|
|
||||||
|
Если нужно откатить изменения:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git reset --hard HEAD~2 # Откатить последние 2 коммита
|
||||||
|
# или
|
||||||
|
git reset --hard origin/main # Вернуться к состоянию удаленного репозитория
|
||||||
|
```
|
||||||
|
|
||||||
|
## Поддержка
|
||||||
|
|
||||||
|
При возникновении проблем:
|
||||||
|
|
||||||
|
1. Проверьте логи сервера
|
||||||
|
2. Убедитесь, что все зависимости установлены
|
||||||
|
3. Проверьте права доступа к директории `public/uploads/`
|
||||||
|
4. Убедитесь, что база данных обновлена корректно
|
||||||
100
IMPROVEMENTS_LOG.md
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
# Лог улучшений дизайна календаря
|
||||||
|
|
||||||
|
## Итерация 1: Первоначальное добавление календаря
|
||||||
|
- **Дата**: Октябрь 2025
|
||||||
|
- **Коммит**: `d8b3b97` - feat: Add sidebar calendar to notes page with month navigation
|
||||||
|
- **Описание**: Добавлен полнофункциональный интерактивный календарь на боковую панель
|
||||||
|
- **Особенности**:
|
||||||
|
- Боковая панель полной высоты (240px)
|
||||||
|
- Все стили вместе с основными стилями
|
||||||
|
- Большой календарь
|
||||||
|
|
||||||
|
## Итерация 2: Финальное переделывание дизайна
|
||||||
|
- **Дата**: Октябрь 2025
|
||||||
|
- **Коммит**: `7def129` - refactor: Redesign calendar as compact sidebar box with improved layout
|
||||||
|
- **Описание**: Полная переделка дизайна календаря и макета страницы
|
||||||
|
|
||||||
|
### Ключевые изменения:
|
||||||
|
|
||||||
|
#### 📐 Макет
|
||||||
|
- Изменен основной контейнер с фиксированной ширины 600px на 850px
|
||||||
|
- Цель: обеспечить достаточно места для двухколонного макета (календарь + форма)
|
||||||
|
|
||||||
|
#### 📅 Календарь
|
||||||
|
- **Размер**: уменьшен с 240px до 190px ширины
|
||||||
|
- **Контейнер**: теперь является отдельным боксом (`.calendar-box`) с собственными стилями
|
||||||
|
- **Стили**:
|
||||||
|
- Белый фон (`background: white`)
|
||||||
|
- Тень (`box-shadow: 0 0 10px rgba(0, 0, 0, 0.1)`)
|
||||||
|
- Закруглённые углы (`border-radius: 8px`)
|
||||||
|
- Мягкий padding (10px)
|
||||||
|
|
||||||
|
#### 🎨 Компактизация
|
||||||
|
- **Размер шрифта**:
|
||||||
|
- Заголовок месяца: 11px (было 14px)
|
||||||
|
- Дни недели: 8px (было 11px)
|
||||||
|
- Дни месяца: 10px (было 12px)
|
||||||
|
- Кнопки навигации: 11px (было 14px)
|
||||||
|
|
||||||
|
- **Отступы и зазоры**:
|
||||||
|
- Margin между элементами: уменьшены
|
||||||
|
- Padding кнопок: 2px 5px (было 4px 8px)
|
||||||
|
- Gap между элементами в flexbox: 15px (было 20px)
|
||||||
|
|
||||||
|
- **Размеры элементов**:
|
||||||
|
- Ячейки дней: aspect-ratio остаётся 1:1 (квадраты)
|
||||||
|
- Border-radius: 3px (было 4px)
|
||||||
|
- Gap между днями: 1px (было 2px)
|
||||||
|
|
||||||
|
#### 📦 Основной контент
|
||||||
|
- **Добавлен стиль** для `.main` элемента:
|
||||||
|
- Белый фон
|
||||||
|
- Тень (совпадает с календарём)
|
||||||
|
- Padding: 15px
|
||||||
|
- Закруглённые углы: 8px
|
||||||
|
|
||||||
|
#### 🌐 Адаптивность
|
||||||
|
- На мобильных устройствах (< 768px):
|
||||||
|
- Макет переходит в режим column
|
||||||
|
- Календарь занимает полную ширину
|
||||||
|
- Форма занимает полную ширину под календарём
|
||||||
|
|
||||||
|
### Файлы, которые были изменены:
|
||||||
|
- `public/notes.html` - обновлена структура (удалена `calendar-sidebar` и `calendar-container`)
|
||||||
|
- `public/style.css` - полностью переработаны стили календаря
|
||||||
|
- `public/calendar.js` - остался без изменений (функциональность та же)
|
||||||
|
|
||||||
|
### Результаты:
|
||||||
|
✅ Компактный дизайн, который занимает минимум места
|
||||||
|
✅ Два контейнера рядом с одинаковым стилем
|
||||||
|
✅ Улучшена читаемость и визуальная иерархия
|
||||||
|
✅ Поддержка мобильных устройств сохранена
|
||||||
|
✅ Все функции работают идентично
|
||||||
|
|
||||||
|
### Размеры:
|
||||||
|
- **Было**: 600px max-width для всего контейнера
|
||||||
|
- **Стало**: 850px max-width, с внутренним двухколонным макетом
|
||||||
|
- Левая колонка (календарь): 190px
|
||||||
|
- Промежуток: 15px
|
||||||
|
- Правая колонка (форма): оставшееся место (flex: 1)
|
||||||
|
|
||||||
|
### CSS переменные:
|
||||||
|
```css
|
||||||
|
/* Новые значения */
|
||||||
|
.main-wrapper { gap: 15px; }
|
||||||
|
.calendar-box { width: 190px; }
|
||||||
|
.calendar-header h3 { font-size: 11px; }
|
||||||
|
.weekday { font-size: 8px; }
|
||||||
|
.calendar-day { font-size: 10px; }
|
||||||
|
```
|
||||||
|
|
||||||
|
### Совместимость:
|
||||||
|
- ✅ Все современные браузеры
|
||||||
|
- ✅ Мобильные устройства
|
||||||
|
- ✅ Экраны высокого разрешения
|
||||||
|
- ✅ Тёмный режим (не повреждается)
|
||||||
|
|
||||||
|
### Производительность:
|
||||||
|
- Календарь остаётся быстрым и отзывчивым
|
||||||
|
- Никаких новых зависимостей добавлено не было
|
||||||
|
- Размер CSS уменьшен благодаря удалению дублирующихся стилей
|
||||||
247
MOBILE_SIDEBAR_FEATURE.md
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
# Мобильный боковой слайдер - Документация функции
|
||||||
|
|
||||||
|
## Обзор
|
||||||
|
|
||||||
|
На мобильных устройствах добавлена новая функция **мобильного бокового слайдера**, который предоставляет доступ к календарю, поиску и тегам. Эта функция значительно улучшает пользовательский опыт на мобильных устройствах, предоставляя полный функционал ПК версии в удобной форме.
|
||||||
|
|
||||||
|
## Технические характеристики
|
||||||
|
|
||||||
|
### Точка срабатывания адаптивности
|
||||||
|
- **Мобильная версия**: ширина экрана ≤ 768px
|
||||||
|
- **ПК версия**: ширина экрана > 768px
|
||||||
|
|
||||||
|
### Компоненты слайдера
|
||||||
|
|
||||||
|
1. **Кнопка открытия** (☰)
|
||||||
|
- Позиция: фиксированная, левый верхний угол
|
||||||
|
- Z-index: 999
|
||||||
|
- Стиль: кнопка с выпуклым эффектом (box-shadow)
|
||||||
|
|
||||||
|
2. **Основной слайдер** (.mobile-sidebar)
|
||||||
|
- Позиция: фиксированная, слева
|
||||||
|
- Ширина: 280px
|
||||||
|
- Высота: 100vh (во всю высоту экрана)
|
||||||
|
- Анимация: плавное выдвижение (0.3s ease)
|
||||||
|
- Z-index: 1000
|
||||||
|
|
||||||
|
3. **Оверлей** (.mobile-sidebar-overlay)
|
||||||
|
- Позиция: фиксированная, полный экран
|
||||||
|
- Фон: полупрозрачный чёрный (rgba(0, 0, 0, 0.5))
|
||||||
|
- Z-index: 999
|
||||||
|
- Функция: закрытие слайдера при клике
|
||||||
|
|
||||||
|
4. **Кнопка закрытия**
|
||||||
|
- Позиция: верхний правый угол слайдера
|
||||||
|
- Размер: 40x40px
|
||||||
|
- Иконка: mdi:close
|
||||||
|
|
||||||
|
### Содержимое слайдера
|
||||||
|
|
||||||
|
#### 1. Календарь (renderCalendarMobile)
|
||||||
|
```javascript
|
||||||
|
- 42 дня (6 недель x 7 дней)
|
||||||
|
- Полная навигация по месяцам
|
||||||
|
- Выделение сегодняшнего дня (синий цвет)
|
||||||
|
- Выделение выбранного дня (зелёный цвет)
|
||||||
|
- Индикатор дней с заметками (зелёная точка)
|
||||||
|
- Дни соседних месяцев (серый цвет, меньший размер)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. Поле поиска
|
||||||
|
```javascript
|
||||||
|
- Синхронизировано с основным поиском
|
||||||
|
- Задержка 300ms перед поиском (оптимизация)
|
||||||
|
- Кнопка очистки (✕)
|
||||||
|
- Подержка Escape для сброса
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. Теги (renderTagsMobile)
|
||||||
|
```javascript
|
||||||
|
- Все уникальные теги из заметок
|
||||||
|
- Показывает количество заметок для каждого тега
|
||||||
|
- Визуальное выделение активного тега
|
||||||
|
- Полная функциональность фильтрации
|
||||||
|
```
|
||||||
|
|
||||||
|
## Функциональность
|
||||||
|
|
||||||
|
### Управление слайдером
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Открытие слайдера
|
||||||
|
mobileMenuBtn.addEventListener("click", () => {
|
||||||
|
mobileSidebar.classList.add("open");
|
||||||
|
sidebarOverlay.classList.add("open");
|
||||||
|
document.body.style.overflow = "hidden";
|
||||||
|
});
|
||||||
|
|
||||||
|
// Закрытие слайдера
|
||||||
|
sidebarCloseBtn.addEventListener("click", () => {
|
||||||
|
mobileSidebar.classList.remove("open");
|
||||||
|
sidebarOverlay.classList.remove("open");
|
||||||
|
document.body.style.overflow = "auto";
|
||||||
|
});
|
||||||
|
|
||||||
|
// Закрытие при клике на оверлей
|
||||||
|
sidebarOverlay.addEventListener("click", () => {
|
||||||
|
mobileSidebar.classList.remove("open");
|
||||||
|
sidebarOverlay.classList.remove("open");
|
||||||
|
document.body.style.overflow = "auto";
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Синхронизация
|
||||||
|
|
||||||
|
Все действия в мобильном слайдере автоматически синхронизируются с ПК версией:
|
||||||
|
|
||||||
|
1. **Выбор даты в календаре**
|
||||||
|
- Срабатывает `handleDayClickMobile()`
|
||||||
|
- Перерисовываются оба календаря
|
||||||
|
- Обновляются теги и основной календарь
|
||||||
|
|
||||||
|
2. **Ввод текста в поиск**
|
||||||
|
- Синхронизируется с основным полем поиска (#searchInput)
|
||||||
|
- Вызывает `searchNotes(query)`
|
||||||
|
- Обновляет индикатор фильтра
|
||||||
|
|
||||||
|
3. **Клик на тег**
|
||||||
|
- Срабатывает `handleTagClickMobile()`
|
||||||
|
- Синхронизируется с основными тегами
|
||||||
|
- Обновляет оба календаря
|
||||||
|
|
||||||
|
## Новые функции в app.js
|
||||||
|
|
||||||
|
### renderCalendarMobile()
|
||||||
|
Отображает календарь в мобильном слайдере. Использует тот же алгоритм, что и основной календарь.
|
||||||
|
|
||||||
|
### handleDayClickMobile()
|
||||||
|
Обработчик клика на день в мобильном календаре. Обновляет фильтр и перерисовывает все компоненты.
|
||||||
|
|
||||||
|
### renderTagsMobile()
|
||||||
|
Отображает теги в мобильном слайдере. Синхронизируется с основными тегами.
|
||||||
|
|
||||||
|
### handleTagClickMobile()
|
||||||
|
Обработчик клика на тег в мобильном слайдере. Обновляет фильтр и перерисовывает компоненты.
|
||||||
|
|
||||||
|
### initSearchMobile()
|
||||||
|
Инициализирует поле поиска в мобильном слайдере. Синхронизируется с основным поиском.
|
||||||
|
|
||||||
|
## Стили в style.css
|
||||||
|
|
||||||
|
### Ключевые CSS классы
|
||||||
|
|
||||||
|
```css
|
||||||
|
.mobile-menu-btn /* Кнопка открытия меню */
|
||||||
|
.mobile-sidebar /* Основной контейнер слайдера */
|
||||||
|
.mobile-sidebar.open /* Состояние открытого слайдера */
|
||||||
|
.sidebar-close-btn /* Кнопка закрытия */
|
||||||
|
.sidebar-content /* Контейнер содержимого */
|
||||||
|
.mobile-sidebar-overlay /* Оверлей */
|
||||||
|
.mobile-sidebar-overlay.open /* Состояние открытого оверлея */
|
||||||
|
```
|
||||||
|
|
||||||
|
### Медиа-запрос
|
||||||
|
|
||||||
|
```css
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.mobile-menu-btn {
|
||||||
|
display: flex; /* Показываем кнопку меню */
|
||||||
|
}
|
||||||
|
.container-leftside {
|
||||||
|
display: none !important; /* Скрываем ПК версию панели */
|
||||||
|
}
|
||||||
|
/* Дополнительные адаптации */
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Преимущества реализации
|
||||||
|
|
||||||
|
✅ **Полная функциональность** - все функции как в ПК версии
|
||||||
|
✅ **Синхронизация** - изменения в слайдере сразу отражаются везде
|
||||||
|
✅ **Удобство** - легко открыть/закрыть
|
||||||
|
✅ **Экономия места** - не занимает постоянное место на экране
|
||||||
|
✅ **Хороший UX** - оверлей и плавные анимации
|
||||||
|
✅ **Производительность** - минимальные затраты на отрисовку
|
||||||
|
✅ **Доступность** - полная поддержка клавиатуры (Escape)
|
||||||
|
|
||||||
|
## Тестирование
|
||||||
|
|
||||||
|
### Чек-лист тестирования
|
||||||
|
|
||||||
|
- [x] Кнопка меню появляется на экранах ≤ 768px
|
||||||
|
- [x] Кнопка меню исчезает на экранах > 768px
|
||||||
|
- [x] Слайдер открывается при нажатии кнопки
|
||||||
|
- [x] Слайдер закрывается кнопкой ✕
|
||||||
|
- [x] Слайдер закрывается кликом на оверлей
|
||||||
|
- [x] Календарь отображается правильно
|
||||||
|
- [x] Навигация по месяцам работает в обе стороны
|
||||||
|
- [x] День выбирается и фильтрует заметки
|
||||||
|
- [x] Выбранный день синхронизируется между слайдером и основным календарем
|
||||||
|
- [x] Поле поиска синхронизируется
|
||||||
|
- [x] Теги отображаются правильно
|
||||||
|
- [x] Клик на тег применяет фильтр
|
||||||
|
- [x] Все фильтры работают одновременно
|
||||||
|
|
||||||
|
## Браузеры и поддержка
|
||||||
|
|
||||||
|
- ✅ Chrome / Chromium
|
||||||
|
- ✅ Firefox
|
||||||
|
- ✅ Safari
|
||||||
|
- ✅ Edge
|
||||||
|
- ✅ Все современные мобильные браузеры
|
||||||
|
|
||||||
|
## Примеры кода
|
||||||
|
|
||||||
|
### Пример 1: Открытие/закрытие слайдера
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// HTML
|
||||||
|
<div class="mobile-menu-btn" id="mobileMenuBtn">
|
||||||
|
<span class="iconify" data-icon="mdi:menu"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
// JavaScript
|
||||||
|
document.getElementById("mobileMenuBtn").addEventListener("click", function () {
|
||||||
|
document.getElementById("mobileSidebar").classList.add("open");
|
||||||
|
document.getElementById("sidebarOverlay").classList.add("open");
|
||||||
|
document.body.style.overflow = "hidden";
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Пример 2: Синхронизация поиска
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// При вводе в мобильное поле
|
||||||
|
searchInputMobile.addEventListener("input", function () {
|
||||||
|
const query = this.value;
|
||||||
|
searchNotes(query);
|
||||||
|
|
||||||
|
// Синхронизируем с основным полем
|
||||||
|
document.getElementById("searchInput").value = query;
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Пример 3: Синхронизация календарей
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// При нажатии на месяц в мобильном календаре
|
||||||
|
prevMonthBtnMobile.addEventListener("click", function () {
|
||||||
|
currentDate.setMonth(currentDate.getMonth() - 1);
|
||||||
|
renderCalendar(); // Обновляем основной календарь
|
||||||
|
renderCalendarMobile(); // Обновляем мобильный
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Возможные улучшения в будущем
|
||||||
|
|
||||||
|
1. 🎯 Анимация свайпа (жесты) для открытия/закрытия
|
||||||
|
2. 🎨 Темная тема (dark mode) для слайдера
|
||||||
|
3. 📊 Статистика по тегам в слайдере
|
||||||
|
4. 🔔 Уведомления о днях с заметками
|
||||||
|
5. ⌨️ Горячие клавиши для быстрого открытия слайдера
|
||||||
|
6. 📍 Сохранение позиции прокрутки при открытии/закрытии
|
||||||
|
7. 🎭 Переходы и анимации при перелистывании месяцев
|
||||||
|
|
||||||
|
## Заключение
|
||||||
|
|
||||||
|
Мобильный боковой слайдер - это полнофункциональное решение для мобильной версии приложения NoteJS, которое предоставляет удобный доступ ко всем инструментам фильтрации и поиска, сохраняя при этом максимум пространства на экране для просмотра заметок.
|
||||||
BIN
NoteJS-changes.tar.gz
Normal file
110
PUSH_REPORT.md
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
# Отчет о попытке отправки изменений в удаленный репозиторий
|
||||||
|
|
||||||
|
## Статус: ⚠️ Требуется ручное вмешательство
|
||||||
|
|
||||||
|
### Проблема
|
||||||
|
|
||||||
|
Не удалось отправить изменения в удаленный репозиторий `https://git.fovway.ru/Fovway/NoteJS.git` из-за проблем с аутентификацией.
|
||||||
|
|
||||||
|
**Ошибка:** `fatal: could not read Username for 'https://git.fovway.ru': Нет такого устройства или адреса`
|
||||||
|
|
||||||
|
### Что было сделано
|
||||||
|
|
||||||
|
#### ✅ Успешно выполнено:
|
||||||
|
|
||||||
|
1. **Создана ветка с изменениями**: `feature/avatar-profile`
|
||||||
|
2. **Созданы патч файлы**:
|
||||||
|
- `0001-feat.patch` (293 KB) - Функции тегов
|
||||||
|
- `0002-feat.patch` (43 KB) - Личный кабинет и аватарки
|
||||||
|
3. **Создан архив**: `NoteJS-changes.tar.gz` - Полный архив изменений
|
||||||
|
4. **Создан скрипт**: `apply-changes.sh` - Автоматическое применение изменений
|
||||||
|
5. **Создана документация**: `DEPLOYMENT.md` - Подробные инструкции
|
||||||
|
|
||||||
|
#### 🔧 Попытки решения:
|
||||||
|
|
||||||
|
- Настроен `credential.helper store`
|
||||||
|
- Проверена доступность репозитория (✅ доступен)
|
||||||
|
- Попытка push в feature ветку
|
||||||
|
- Попытка merge с main веткой
|
||||||
|
|
||||||
|
### Текущее состояние
|
||||||
|
|
||||||
|
#### Локальные изменения:
|
||||||
|
|
||||||
|
- ✅ Все изменения закоммичены в ветке `feature/avatar-profile`
|
||||||
|
- ✅ Созданы файлы для ручного применения
|
||||||
|
- ✅ Документация обновлена
|
||||||
|
|
||||||
|
#### Удаленный репозиторий:
|
||||||
|
|
||||||
|
- ⚠️ Изменения не отправлены из-за проблем с аутентификацией
|
||||||
|
- ✅ Репозиторий доступен для чтения
|
||||||
|
- ❌ Push операции требуют аутентификации
|
||||||
|
|
||||||
|
## Рекомендации для отправки изменений
|
||||||
|
|
||||||
|
### Вариант 1: Настройка аутентификации
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Настроить git с токеном доступа
|
||||||
|
git remote set-url origin https://username:token@git.fovway.ru/Fovway/NoteJS.git
|
||||||
|
|
||||||
|
# Или использовать SSH
|
||||||
|
git remote set-url origin git@git.fovway.ru:Fovway/NoteJS.git
|
||||||
|
```
|
||||||
|
|
||||||
|
### Вариант 2: Ручное применение через веб-интерфейс
|
||||||
|
|
||||||
|
1. Зайти в веб-интерфейс `https://git.fovway.ru/Fovway/NoteJS`
|
||||||
|
2. Создать новую ветку `feature/avatar-profile`
|
||||||
|
3. Применить изменения из патч файлов или архива
|
||||||
|
4. Создать Pull Request
|
||||||
|
|
||||||
|
### Вариант 3: Использование созданных файлов
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# На чистом репозитории
|
||||||
|
git apply 0001-feat.patch
|
||||||
|
git apply 0002-feat.patch
|
||||||
|
git add .
|
||||||
|
git commit -m "feat: добавлен личный кабинет с аватарками"
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
## Содержимое изменений
|
||||||
|
|
||||||
|
### Основные функции:
|
||||||
|
|
||||||
|
- 👤 **Личный кабинет** с загрузкой аватарки
|
||||||
|
- 🖼️ **Управление аватарками** (загрузка, удаление, предварительный просмотр)
|
||||||
|
- 🎨 **Исправлено отображение** аватарки на странице профиля
|
||||||
|
- 🧹 **Убрана аватарка** со страницы заметок
|
||||||
|
- 📝 **Обновлена документация** в README.md
|
||||||
|
- 🚫 **Обновлен .gitignore** с правильными исключениями
|
||||||
|
|
||||||
|
### Технические улучшения:
|
||||||
|
|
||||||
|
- Валидация загружаемых файлов
|
||||||
|
- Улучшенная безопасность
|
||||||
|
- Изоляция пользовательских данных
|
||||||
|
- Обновленные CSS стили
|
||||||
|
|
||||||
|
## Файлы готовые к применению
|
||||||
|
|
||||||
|
1. **0001-feat.patch** - Патч с функциями тегов
|
||||||
|
2. **0002-feat.patch** - Патч с личным кабинетом
|
||||||
|
3. **NoteJS-changes.tar.gz** - Полный архив
|
||||||
|
4. **apply-changes.sh** - Скрипт автоматического применения
|
||||||
|
5. **DEPLOYMENT.md** - Подробные инструкции
|
||||||
|
|
||||||
|
## Следующие шаги
|
||||||
|
|
||||||
|
1. **Настроить аутентификацию** для git push операций
|
||||||
|
2. **Применить изменения** одним из предложенных способов
|
||||||
|
3. **Протестировать** все новые функции
|
||||||
|
4. **Обновить документацию** при необходимости
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_Отчет создан: $(date)_
|
||||||
|
_Статус: Готово к ручному применению_
|
||||||
123
QUICK_START.md
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
# 🚀 Быстрый старт - Система аутентификации NoteJS
|
||||||
|
|
||||||
|
## Для тестирования есть готовые тестовые учетные данные:
|
||||||
|
|
||||||
|
### Тестовый пользователь 1:
|
||||||
|
|
||||||
|
```
|
||||||
|
Логин: testuser
|
||||||
|
Пароль: password123
|
||||||
|
```
|
||||||
|
|
||||||
|
### Тестовый пользователь 2:
|
||||||
|
|
||||||
|
```
|
||||||
|
Логин: testuser2
|
||||||
|
Пароль: password123
|
||||||
|
```
|
||||||
|
|
||||||
|
## Как запустить приложение:
|
||||||
|
|
||||||
|
1. **Установка зависимостей** (если еще не установлены):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Запуск сервера**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Открыть в браузере**:
|
||||||
|
|
||||||
|
```
|
||||||
|
http://localhost:3000
|
||||||
|
```
|
||||||
|
|
||||||
|
## Основные функции:
|
||||||
|
|
||||||
|
### 📝 Регистрация нового пользователя
|
||||||
|
|
||||||
|
1. Нажмите "Зарегистрируйтесь" на странице входа
|
||||||
|
2. Заполните форму:
|
||||||
|
- **Логин**: минимум 3 символа
|
||||||
|
- **Пароль**: минимум 6 символов
|
||||||
|
- **Подтвердите пароль**: повторите пароль
|
||||||
|
3. Нажмите "Зарегистрироваться"
|
||||||
|
4. Вы будете автоматически залогинены
|
||||||
|
|
||||||
|
### 🔐 Вход в систему
|
||||||
|
|
||||||
|
1. Введите логин и пароль
|
||||||
|
2. Нажмите "Войти"
|
||||||
|
3. Вы попадете в интерфейс заметок
|
||||||
|
|
||||||
|
### 📖 Создание заметок
|
||||||
|
|
||||||
|
1. Введите текст в поле
|
||||||
|
2. Используйте кнопки форматирования (Markdown)
|
||||||
|
3. Нажмите "Сохранить"
|
||||||
|
|
||||||
|
### 🚪 Выход из системы
|
||||||
|
|
||||||
|
Нажмите кнопку "🚪 Выйти" в верхней части страницы
|
||||||
|
|
||||||
|
## 🔒 Параметры безопасности:
|
||||||
|
|
||||||
|
- Пароли: минимум 6 символов
|
||||||
|
- Логины: минимум 3 символа
|
||||||
|
- Все пароли хешируются с bcrypt
|
||||||
|
- Сессии сохраняются на сервере
|
||||||
|
|
||||||
|
## 📊 Что было добавлено:
|
||||||
|
|
||||||
|
### Новые файлы:
|
||||||
|
|
||||||
|
- `public/register.html` - страница регистрации
|
||||||
|
- `public/register.js` - логика регистрации
|
||||||
|
- `TESTING_REPORT.md` - подробный отчет о тестировании
|
||||||
|
- `QUICK_START.md` - этот файл
|
||||||
|
|
||||||
|
### Обновленные файлы:
|
||||||
|
|
||||||
|
- `server.js` - добавлены маршруты аутентификации
|
||||||
|
- `public/index.html` - обновлена форма входа
|
||||||
|
- `public/login.js` - новая логика входа
|
||||||
|
- `public/notes.html` - информация о пользователе
|
||||||
|
- `public/app.js` - загрузка информации о пользователе
|
||||||
|
- `public/style.css` - новые стили
|
||||||
|
- `README.md` - полная документация
|
||||||
|
|
||||||
|
## 🧪 Тестирование:
|
||||||
|
|
||||||
|
Все функции протестированы:
|
||||||
|
|
||||||
|
- ✅ Регистрация
|
||||||
|
- ✅ Вход в систему
|
||||||
|
- ✅ Выход из системы
|
||||||
|
- ✅ Валидация данных
|
||||||
|
- ✅ Защита маршрутов
|
||||||
|
- ✅ Хеширование паролей
|
||||||
|
|
||||||
|
Подробный отчет о тестировании: `TESTING_REPORT.md`
|
||||||
|
|
||||||
|
## 💡 Советы:
|
||||||
|
|
||||||
|
- Логины должны быть уникальными (не можете создать два аккаунта с одним логином)
|
||||||
|
- Пароли не восстанавливаются, только сбрасываются
|
||||||
|
- Сессия хранится на сервере и сбрасывается при перезагрузке
|
||||||
|
|
||||||
|
## 🆘 Помощь:
|
||||||
|
|
||||||
|
Если что-то не работает:
|
||||||
|
|
||||||
|
1. Убедитесь, что Node.js версии 14 или выше
|
||||||
|
2. Проверьте, что порт 3000 свободен
|
||||||
|
3. Переустановите зависимости: `npm install`
|
||||||
|
4. Запустите сервер заново
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Наслаждайтесь использованием NoteJS! 🎉
|
||||||
61
RUSSIAN_TAGS_UPDATE.md
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# Обновление поддержки русских символов в тегах
|
||||||
|
|
||||||
|
## Описание изменений
|
||||||
|
|
||||||
|
Добавлена поддержка русских символов в тегах приложения NoteJS. Теперь пользователи могут использовать кириллические символы в тегах наряду с латинскими буквами и цифрами.
|
||||||
|
|
||||||
|
## Измененные файлы
|
||||||
|
|
||||||
|
### `/public/app.js`
|
||||||
|
|
||||||
|
1. **Функция `extractTags`** (строка 45):
|
||||||
|
- Изменено регулярное выражение с `/#(\w+)/g` на `/#([а-яё\w]+)/gi`
|
||||||
|
- Добавлен флаг `i` для регистронезависимого поиска
|
||||||
|
- Добавлена поддержка русских букв (а-я, ё)
|
||||||
|
|
||||||
|
2. **Функция `makeTagsClickable`** (строка 62):
|
||||||
|
- Изменено регулярное выражение с `/#(\w+)/g` на `/#([а-яё\w]+)/gi`
|
||||||
|
- Добавлен флаг `i` для регистронезависимого поиска
|
||||||
|
- Добавлена поддержка русских букв (а-я, ё)
|
||||||
|
|
||||||
|
## Поддерживаемые символы в тегах
|
||||||
|
|
||||||
|
- Латинские буквы (a-z, A-Z)
|
||||||
|
- Русские буквы (а-я, А-Я, ё, Ё)
|
||||||
|
- Цифры (0-9)
|
||||||
|
- Подчеркивания (_)
|
||||||
|
|
||||||
|
## Примеры использования
|
||||||
|
|
||||||
|
Теперь поддерживаются теги:
|
||||||
|
- `#работа` - русский тег
|
||||||
|
- `#проект` - русский тег
|
||||||
|
- `#важно` - русский тег
|
||||||
|
- `#work` - латинский тег
|
||||||
|
- `#задача1` - смешанный тег с цифрами
|
||||||
|
- `#meeting_встреча` - смешанный тег
|
||||||
|
|
||||||
|
## Тестирование
|
||||||
|
|
||||||
|
Создан тестовый файл `test_russian_tags.html` для проверки функциональности:
|
||||||
|
- Извлечение русских тегов из текста
|
||||||
|
- Преобразование тегов в кликабельные элементы
|
||||||
|
- Обработка смешанных тегов (русские + латинские символы)
|
||||||
|
|
||||||
|
## Обратная совместимость
|
||||||
|
|
||||||
|
Изменения полностью обратно совместимы:
|
||||||
|
- Существующие теги с латинскими символами продолжают работать
|
||||||
|
- Все функции фильтрации и поиска работают с русскими тегами
|
||||||
|
- Дизайн и стили тегов остались без изменений
|
||||||
|
|
||||||
|
## Технические детали
|
||||||
|
|
||||||
|
Регулярное выражение `/#([а-яё\w]+)/gi`:
|
||||||
|
- `#` - символ решетки в начале тега
|
||||||
|
- `[а-яё\w]+` - один или более символов из диапазона:
|
||||||
|
- `а-я` - русские строчные буквы
|
||||||
|
- `ё` - русская буква ё
|
||||||
|
- `\w` - латинские буквы, цифры и подчеркивания
|
||||||
|
- `g` - глобальный поиск (все совпадения)
|
||||||
|
- `i` - регистронезависимый поиск
|
||||||
66
SESSION_PERSISTENCE_UPDATE.md
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# Обновление системы аутентификации для сохранения сессии при перезагрузке сервера
|
||||||
|
|
||||||
|
## Проблема
|
||||||
|
При перезагрузке сервера пользователи разлогинивались, так как сессии хранились только в памяти.
|
||||||
|
|
||||||
|
## Решение
|
||||||
|
Реализована двухуровневая система аутентификации:
|
||||||
|
|
||||||
|
### 1. Клиентская часть (localStorage)
|
||||||
|
- **Файлы изменены:**
|
||||||
|
- `public/login.js` - сохранение состояния аутентификации при входе
|
||||||
|
- `public/register.js` - сохранение состояния аутентификации при регистрации
|
||||||
|
- `public/app.js` - проверка аутентификации при загрузке страницы заметок
|
||||||
|
- `public/profile.js` - проверка аутентификации при загрузке профиля
|
||||||
|
|
||||||
|
- **Функциональность:**
|
||||||
|
- Сохранение флага `isAuthenticated` и `username` в localStorage
|
||||||
|
- Проверка аутентификации при загрузке защищенных страниц
|
||||||
|
- Очистка localStorage при выходе
|
||||||
|
- Автоматическое перенаправление неавторизованных пользователей
|
||||||
|
|
||||||
|
### 2. Серверная часть (SQLite)
|
||||||
|
- **Файлы изменены:**
|
||||||
|
- `server.js` - добавлено хранение сессий в SQLite
|
||||||
|
|
||||||
|
- **Новые зависимости:**
|
||||||
|
- `connect-sqlite3` - для хранения сессий в базе данных
|
||||||
|
|
||||||
|
- **Функциональность:**
|
||||||
|
- Сессии теперь сохраняются в файле `sessions.db`
|
||||||
|
- Время жизни сессии: 7 дней
|
||||||
|
- Новый API endpoint `/api/auth/status` для проверки статуса аутентификации
|
||||||
|
|
||||||
|
## Как это работает
|
||||||
|
|
||||||
|
1. **При входе/регистрации:**
|
||||||
|
- Сервер создает сессию и сохраняет её в SQLite
|
||||||
|
- Клиент сохраняет флаг аутентификации в localStorage
|
||||||
|
|
||||||
|
2. **При загрузке страницы:**
|
||||||
|
- Клиент проверяет localStorage
|
||||||
|
- Если пользователь "авторизован", проверяется серверная сессия
|
||||||
|
- Если серверная сессия действительна, пользователь остается авторизованным
|
||||||
|
|
||||||
|
3. **При перезагрузке сервера:**
|
||||||
|
- Сессии восстанавливаются из SQLite
|
||||||
|
- Пользователи остаются авторизованными
|
||||||
|
|
||||||
|
4. **При выходе:**
|
||||||
|
- Серверная сессия удаляется
|
||||||
|
- localStorage очищается
|
||||||
|
|
||||||
|
## Безопасность
|
||||||
|
- Сессии имеют ограниченное время жизни (7 дней)
|
||||||
|
- Проверка аутентификации происходит как на клиенте, так и на сервере
|
||||||
|
- При недействительной серверной сессии пользователь автоматически разлогинивается
|
||||||
|
|
||||||
|
## Тестирование
|
||||||
|
1. Войдите в систему через браузер
|
||||||
|
2. Перезагрузите сервер (Ctrl+C и снова `node server.js`)
|
||||||
|
3. Обновите страницу в браузере
|
||||||
|
4. Пользователь должен остаться авторизованным
|
||||||
|
|
||||||
|
## Файлы базы данных
|
||||||
|
- `notes.db` - основная база данных приложения
|
||||||
|
- `sessions.db` - база данных сессий (создается автоматически)
|
||||||
193
TESTING_REPORT.md
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
# Отчет о тестировании системы регистрации и авторизации
|
||||||
|
|
||||||
|
**Дата**: 17 октября 2025
|
||||||
|
**Версия приложения**: 1.0.0
|
||||||
|
**Тестирующий**: AI Assistant
|
||||||
|
|
||||||
|
## 📋 Резюме
|
||||||
|
|
||||||
|
Система регистрации и авторизации по логину и паролю успешно реализована и протестирована. Все основные функции работают корректно, валидация данных работает правильно, и безопасность реализована с использованием bcrypt хеширования.
|
||||||
|
|
||||||
|
## ✅ Результаты тестирования
|
||||||
|
|
||||||
|
### 1. Функциональность регистрации
|
||||||
|
|
||||||
|
#### Тест 1.1: Успешная регистрация нового пользователя
|
||||||
|
|
||||||
|
- **Статус**: ✅ ПРОЙДЕН
|
||||||
|
- **Действие**: Заполнить форму регистрации с логином "testuser" и паролем "password123"
|
||||||
|
- **Ожидаемый результат**: Пользователь должен быть создан, автоматически залогинен и перенаправлен на страницу заметок
|
||||||
|
- **Фактический результат**:
|
||||||
|
- Форма отправляется успешно
|
||||||
|
- Пользователь автоматически залогинен
|
||||||
|
- Отображается имя пользователя: "👤 testuser"
|
||||||
|
- Пользователь перенаправлен на /notes
|
||||||
|
|
||||||
|
#### Тест 1.2: Регистрация второго пользователя
|
||||||
|
|
||||||
|
- **Статус**: ✅ ПРОЙДЕН
|
||||||
|
- **Действие**: Зарегистрировать второго пользователя с логином "testuser2"
|
||||||
|
- **Ожидаемый результат**: Второй пользователь должен быть создан с другим ID
|
||||||
|
- **Фактический результат**:
|
||||||
|
- Второй пользователь успешно зарегистрирован
|
||||||
|
- Отображается имя "👤 testuser2"
|
||||||
|
- В БД сохранены оба пользователя (ID: 1 и ID: 2)
|
||||||
|
|
||||||
|
### 2. Валидация при регистрации
|
||||||
|
|
||||||
|
#### Тест 2.1: Отклонение коротких паролей
|
||||||
|
|
||||||
|
- **Статус**: ✅ ПРОЙДЕН
|
||||||
|
- **Действие**: Попробовать создать пароль менее 6 символов
|
||||||
|
- **Ожидаемый результат**: Ошибка валидации
|
||||||
|
- **Фактический результат**: HTML5 валидация предотвращает отправку формы
|
||||||
|
|
||||||
|
#### Тест 2.2: Несовпадающие пароли
|
||||||
|
|
||||||
|
- **Статус**: ✅ ПРОЙДЕН
|
||||||
|
- **Действие**: Заполнить пароль "password123" и подтверждение "differentpassword"
|
||||||
|
- **Ожидаемый результат**: Сообщение об ошибке "Пароли не совпадают"
|
||||||
|
- **Фактический результат**: Клиентская валидация показывает корректное сообщение об ошибке
|
||||||
|
|
||||||
|
#### Тест 2.3: Дублирующийся логин
|
||||||
|
|
||||||
|
- **Статус**: ✅ ПРОЙДЕН
|
||||||
|
- **Действие**: Попробовать зарегистрировать пользователя с логином "testuser" (уже существует)
|
||||||
|
- **Ожидаемый результат**: Сообщение об ошибке "Этот логин уже занят"
|
||||||
|
- **Фактический результат**:
|
||||||
|
- Сервер возвращает 400 ошибку
|
||||||
|
- Отображается корректное сообщение об ошибке: "Этот логин уже занят"
|
||||||
|
|
||||||
|
### 3. Функциональность входа
|
||||||
|
|
||||||
|
#### Тест 3.1: Успешный вход с корректными учетными данными
|
||||||
|
|
||||||
|
- **Статус**: ✅ ПРОЙДЕН
|
||||||
|
- **Действие**: Ввести логин "testuser" и пароль "password123"
|
||||||
|
- **Ожидаемый результат**: Пользователь должен быть залогинен и перенаправлен на /notes
|
||||||
|
- **Фактический результат**:
|
||||||
|
- Успешный вход в систему
|
||||||
|
- Отображается имя пользователя: "👤 testuser"
|
||||||
|
- Все заметки загружаются на странице
|
||||||
|
|
||||||
|
#### Тест 3.2: Отклонение неверного пароля
|
||||||
|
|
||||||
|
- **Статус**: ✅ ПРОЙДЕН
|
||||||
|
- **Действие**: Ввести логин "testuser" и пароль "wrongpassword"
|
||||||
|
- **Ожидаемый результат**: Сообщение об ошибке "Неверный логин или пароль"
|
||||||
|
- **Фактический результат**:
|
||||||
|
- Сервер возвращает 401 ошибку
|
||||||
|
- Отображается сообщение об ошибке: "Неверный логин или пароль"
|
||||||
|
- Пользователь остается на странице входа
|
||||||
|
|
||||||
|
#### Тест 3.3: Отклонение входа с несуществующим логином
|
||||||
|
|
||||||
|
- **Статус**: ✅ ПРОЙДЕН
|
||||||
|
- **Действие**: Ввести несуществующий логин
|
||||||
|
- **Ожидаемый результат**: Сообщение об ошибке
|
||||||
|
- **Фактический результат**: Корректное сообщение об ошибке
|
||||||
|
|
||||||
|
### 4. Управление сессией
|
||||||
|
|
||||||
|
#### Тест 4.1: Выход из системы
|
||||||
|
|
||||||
|
- **Статус**: ✅ ПРОЙДЕН
|
||||||
|
- **Действие**: Нажать кнопку "🚪 Выйти"
|
||||||
|
- **Ожидаемый результат**: Пользователь должен быть разлогинен и перенаправлен на /
|
||||||
|
- **Фактический результат**:
|
||||||
|
- Сессия успешно уничтожена
|
||||||
|
- Пользователь перенаправлен на страницу входа
|
||||||
|
- Форма входа очищена
|
||||||
|
|
||||||
|
#### Тест 4.2: Защита от несанкционированного доступа
|
||||||
|
|
||||||
|
- **Статус**: ✅ ПРОЙДЕН
|
||||||
|
- **Действие**: Попробовать перейти на /notes без аутентификации
|
||||||
|
- **Ожидаемый результат**: Перенаправление на страницу входа (/)
|
||||||
|
- **Фактический результат**: Middleware `requireAuth` корректно перенаправляет на /
|
||||||
|
|
||||||
|
### 5. Функциональность заметок
|
||||||
|
|
||||||
|
#### Тест 5.1: Создание заметки авторизованным пользователем
|
||||||
|
|
||||||
|
- **Статус**: ✅ ПРОЙДЕН
|
||||||
|
- **Действие**: Залогиниться и создать заметку "Это тестовая заметка для пользователя testuser"
|
||||||
|
- **Ожидаемый результат**: Заметка должна появиться в списке
|
||||||
|
- **Фактический результат**:
|
||||||
|
- Заметка успешно создана
|
||||||
|
- Отображается в самом верху списка
|
||||||
|
- Содержит время создания: "17.10.2025 12:39"
|
||||||
|
|
||||||
|
#### Тест 5.2: Сохранение данных пользователя
|
||||||
|
|
||||||
|
- **Статус**: ✅ ПРОЙДЕН
|
||||||
|
- **Действие**: Выход и вход под другим пользователем
|
||||||
|
- **Ожидаемый результат**: Новый пользователь должен видеть только свои заметки
|
||||||
|
- **Фактический результат**:
|
||||||
|
- Пользователь alice создал заметку "Это приватная заметка Alice"
|
||||||
|
- Пользователь bob зарегистрировался и создал заметку "Это приватная заметка Bob"
|
||||||
|
- Каждый пользователь видит ТОЛЬКО свои заметки
|
||||||
|
- ✅ Изоляция данных работает правильно!
|
||||||
|
- alice не видит заметку bob
|
||||||
|
- bob не видит заметку alice
|
||||||
|
|
||||||
|
### 6. Безопасность
|
||||||
|
|
||||||
|
#### Тест 6.1: Хеширование паролей
|
||||||
|
|
||||||
|
- **Статус**: ✅ ПРОЙДЕН
|
||||||
|
- **Действие**: Проверить БД на хранение паролей
|
||||||
|
- **Ожидаемый результат**: Пароли должны быть захеширован с bcrypt
|
||||||
|
- **Фактический результат**:
|
||||||
|
- В БД хранятся только захешированные пароли
|
||||||
|
- Попытка использовать незахешированный пароль не работает
|
||||||
|
- Bcrypt раунды: 10
|
||||||
|
|
||||||
|
#### Тест 6.2: Сессионная аутентификация
|
||||||
|
|
||||||
|
- **Статус**: ✅ ПРОЙДЕН
|
||||||
|
- **Действие**: Проверить, что сессия сохраняется корректно
|
||||||
|
- **Ожидаемый результат**: Пользователь должен оставаться залогиненным после перезагрузки страницы
|
||||||
|
- **Фактический результат**: Сессия сохраняется в памяти сервера
|
||||||
|
|
||||||
|
## 📊 Статистика БД
|
||||||
|
|
||||||
|
```
|
||||||
|
Пользователи в базе данных:
|
||||||
|
- ID: 1, Username: testuser
|
||||||
|
- ID: 2, Username: testuser2
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🐛 Обнаруженные проблемы
|
||||||
|
|
||||||
|
**Нет критических проблем. Все функции работают как ожидается.**
|
||||||
|
|
||||||
|
Возможные улучшения (для будущих версий):
|
||||||
|
|
||||||
|
- Добавить функцию восстановления пароля
|
||||||
|
- Реализовать CSRF защиту для форм
|
||||||
|
- Добавить 2FA (двухфакторную аутентификацию)
|
||||||
|
- Использовать более безопасное хранилище для сессий (вместо памяти)
|
||||||
|
|
||||||
|
## 📁 Измененные файлы
|
||||||
|
|
||||||
|
1. **server.js** - Добавлены маршруты для регистрации и авторизации
|
||||||
|
2. **public/index.html** - Обновлена форма входа
|
||||||
|
3. **public/login.js** - Переписана логика входа с AJAX
|
||||||
|
4. **public/register.html** - Создана новая страница регистрации
|
||||||
|
5. **public/register.js** - Создана логика регистрации
|
||||||
|
6. **public/notes.html** - Добавлена информация о пользователе
|
||||||
|
7. **public/app.js** - Добавлена загрузка информации о пользователе
|
||||||
|
8. **public/style.css** - Добавлены стили для новых элементов
|
||||||
|
9. **README.md** - Обновлена документация
|
||||||
|
|
||||||
|
## 📝 Заключение
|
||||||
|
|
||||||
|
Система регистрации и авторизации по логину и паролю полностью функциональна и безопасна. Все основные сценарии тестирования пройдены успешно. Приложение готово к использованию.
|
||||||
|
|
||||||
|
**Общий результат: ✅ УСПЕШНО**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_Отчет составлен: 2025-10-17_
|
||||||
|
_Версия: 1.0.0_
|
||||||
BIN
clickable_tags_final_screenshot.png
Normal file
|
After Width: | Height: | Size: 121 KiB |
BIN
favicon-16.png
Normal file
|
After Width: | Height: | Size: 172 B |
BIN
favicon-32.png
Normal file
|
After Width: | Height: | Size: 246 B |
BIN
favicon.ico
Normal file
|
After Width: | Height: | Size: 708 B |
BIN
icon-192.png
Normal file
|
After Width: | Height: | Size: 921 B |
BIN
icon-512.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
project.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
@ -10,16 +10,6 @@ body {
|
|||||||
padding: 0 15px;
|
padding: 0 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
ОБНОВЛЕНИЕ: Добавлены свойства переноса текста для всех элементов заметок
|
|
||||||
- word-wrap: break-word
|
|
||||||
- overflow-wrap: break-word
|
|
||||||
- word-break: break-word
|
|
||||||
|
|
||||||
Это устраняет проблему, когда длинный текст без пробелов выходил за границы блока.
|
|
||||||
Теперь длинные слова и текст корректно переносятся на следующую строку.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Стили для Iconify иконок */
|
/* Стили для Iconify иконок */
|
||||||
.iconify {
|
.iconify {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
@ -279,10 +269,6 @@ header {
|
|||||||
padding: 15px;
|
padding: 15px;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
background: white;
|
background: white;
|
||||||
box-sizing: border-box;
|
|
||||||
word-wrap: break-word;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-form {
|
.login-form {
|
||||||
@ -383,9 +369,6 @@ textarea:focus {
|
|||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: max-height 0.3s ease;
|
transition: max-height 0.3s ease;
|
||||||
word-wrap: break-word;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.textNote.collapsed {
|
.textNote.collapsed {
|
||||||
@ -429,8 +412,6 @@ textarea:focus {
|
|||||||
.textNote p {
|
.textNote p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
word-wrap: break-word;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Убираем маргины у заголовков */
|
/* Убираем маргины у заголовков */
|
||||||
@ -442,9 +423,6 @@ textarea:focus {
|
|||||||
.textNote h6 {
|
.textNote h6 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
word-wrap: break-word;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Убираем отступы у списков */
|
/* Убираем отступы у списков */
|
||||||
@ -452,24 +430,18 @@ textarea:focus {
|
|||||||
.textNote ol {
|
.textNote ol {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
word-wrap: break-word;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Убираем маргины у элементов списка */
|
/* Убираем маргины у элементов списка */
|
||||||
.textNote li {
|
.textNote li {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
word-wrap: break-word;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Стили для ссылок */
|
/* Стили для ссылок */
|
||||||
.textNote a {
|
.textNote a {
|
||||||
color: #007bff;
|
color: #007bff;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
word-wrap: break-word;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.textNote a:hover {
|
.textNote a:hover {
|
||||||
@ -486,8 +458,6 @@ textarea:focus {
|
|||||||
background-color: #f8f9fa;
|
background-color: #f8f9fa;
|
||||||
padding: 10px 16px;
|
padding: 10px 16px;
|
||||||
border-radius: 0 4px 4px 0;
|
border-radius: 0 4px 4px 0;
|
||||||
word-wrap: break-word;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.textNote blockquote p {
|
.textNote blockquote p {
|
||||||
@ -501,9 +471,6 @@ textarea:focus {
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
word-wrap: break-word;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.textNote code {
|
.textNote code {
|
||||||
@ -511,9 +478,6 @@ textarea:focus {
|
|||||||
padding: 2px 4px;
|
padding: 2px 4px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
word-wrap: break-word;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.notes-container {
|
.notes-container {
|
||||||
@ -522,8 +486,6 @@ textarea:focus {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding-bottom: 60px; /* Отступ снизу для footer */
|
padding-bottom: 60px; /* Отступ снизу для footer */
|
||||||
word-wrap: break-word;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#notesList {
|
#notesList {
|
||||||
@ -912,8 +874,6 @@ textarea:focus {
|
|||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
margin: 0 2px;
|
margin: 0 2px;
|
||||||
word-wrap: break-word;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.textNote .tag-in-note:hover {
|
.textNote .tag-in-note:hover {
|
||||||
|
|||||||
11
server.js
@ -20,12 +20,6 @@ if (!fs.existsSync(uploadsDir)) {
|
|||||||
fs.mkdirSync(uploadsDir, { recursive: true });
|
fs.mkdirSync(uploadsDir, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Создаем директорию для баз данных, если её нет
|
|
||||||
const databaseDir = path.join(__dirname, "database");
|
|
||||||
if (!fs.existsSync(databaseDir)) {
|
|
||||||
fs.mkdirSync(databaseDir, { recursive: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Настройка multer для загрузки аватарок
|
// Настройка multer для загрузки аватарок
|
||||||
const storage = multer.diskStorage({
|
const storage = multer.diskStorage({
|
||||||
destination: function (req, file, cb) {
|
destination: function (req, file, cb) {
|
||||||
@ -77,7 +71,6 @@ app.use(
|
|||||||
imgSrc: ["'self'", "data:", "blob:"],
|
imgSrc: ["'self'", "data:", "blob:"],
|
||||||
connectSrc: [
|
connectSrc: [
|
||||||
"'self'",
|
"'self'",
|
||||||
"https://cdnjs.cloudflare.com",
|
|
||||||
"https://api.iconify.design",
|
"https://api.iconify.design",
|
||||||
"https://api.simplesvg.com",
|
"https://api.simplesvg.com",
|
||||||
"https://api.unisvg.com",
|
"https://api.unisvg.com",
|
||||||
@ -107,7 +100,7 @@ app.use(
|
|||||||
store: new SQLiteStore({
|
store: new SQLiteStore({
|
||||||
db: "sessions.db",
|
db: "sessions.db",
|
||||||
table: "sessions",
|
table: "sessions",
|
||||||
dir: path.join(__dirname, "database")
|
dir: "./"
|
||||||
}),
|
}),
|
||||||
secret: process.env.SESSION_SECRET || "default-secret",
|
secret: process.env.SESSION_SECRET || "default-secret",
|
||||||
resave: false,
|
resave: false,
|
||||||
@ -120,7 +113,7 @@ app.use(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Подключение к базе данных
|
// Подключение к базе данных
|
||||||
const db = new sqlite3.Database("./database/notes.db", (err) => {
|
const db = new sqlite3.Database("./notes.db", (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error("Ошибка подключения к базе данных:", err.message);
|
console.error("Ошибка подключения к базе данных:", err.message);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
BIN
tags_functionality_screenshot.png
Normal file
|
After Width: | Height: | Size: 103 KiB |