Привет, Хабр! В свободное от работы время я занимаюсь разработкой своего проекта. На днях мне понадобилось разработать раздел с календарем и задачами, чтобы пользователи могли отслеживать свою деятельность. Увы, но полностью готовых решений я не нашел. API стандартного календаря Google не подходит, так как данные хочу хранить внутри контура проект.
Спустя несколько часов поисков я наткнулся на плейлист разработчиков из Индии. В жизни все циклично — именно эти видео мне и помогли. Так я познакомился с классной open source-библиотекой FullCalendar, о которой расскажу в этой статье. Если вы уже начали составлять календари на 2025 год, добро пожаловать под кат!
Что за библиотека
FullCalendar — это open source-библиотека, которая позволяет создавать кастомные календари без лишних ручек по части бэкенда. Почти полностью фронтенд-решение, которое можно интегрировать без особых навыков. Есть версии как на чистом JavaScript, так и на React, Vue и старом добром Angular.
Главная страница FullCalendar.
Чем понравился FullCalendar
Есть два ограничения, которые я должен был учитывать при поиске решения. Первое: я не самый лучший фронтендер. Второе: мой проект построен на Django. Я убежден, что поиск решения — это всегда перебор разных вариантов, поэтому разводить лишний dependency hell из всяких React и Vue не хотелось.
Это open source
При интеграции вы получаете не какой-то iframe, а полноценный DOM-объект. Это значит, вы можете изменять CSS-стили для элементов календаря и обрабатывать события, связанные с ними. Это полезно, если нужно, например, показывать поп-апы по клику на конкретное задание.
Как я стилизовал стандартный шаблон под мобильный календарь.
Есть версия на нативном JavaScript
FullCalendar подкупил именно наличием версии из нативного JavaScript. Если не понравится, можно просто удалить link-импорты — и проект снова чистый. Но как это иногда бывает, любовь с первого взгляда превратилась в нечто большее.
Есть версия для бэкендеров с лапками
Нативный JavaScript — это хорошо. Но с учетом того, что и его я знаю так себе, не помешал бы Jquery. Разработчики FullCalendar предусмотрели и это. На каждый тип календаря, как я понял, есть две версии: расширенная (нативный JavaScript) и упрощенная (Jquery). К слову, версия с Jquery неплохая, для моего MVP подходит более чем.
Есть документация с песочницей
Очень порадовало, что на главном сайте библиотеки есть раздел Demos, в котором расположены самые популярные форматы календарей. Можно выбрать понравившийся, открыть его в Codepen и переиспользовать.
Раздел Demos с разными типами календарей.
Все — в JSON
Вам не нужно описывать логику генерации и отображения событий внутри календаря, все это сделано уже разработчиками. Просто даете ссылку на JSON-файл со списком событий, а дальше библиотека сама их разместит в колонках календаря. Требуемая структура описана в документации.
$(function() { $('#calendar').fullCalendar({ defaultView: 'agendaWeek', header: { left: 'prev,next today', center: 'title', right: 'agendaWeek,agendaDay' }, // вот эта ссылка может быть размещена локально или в вашем S3 events: 'https://fullcalendar.io/api/demo-feeds/events.json' }) });
Как сделать свой календарь
Рассмотрим реализацию календаря, на примере самого классического шаблона, в котором уже реализована механика, приближенная к Google Calendar.
Шаг 1. Прикрутите фронтенд
Неважно, на чем у вас построено веб-приложение. Откройте шаблон вашего календаря и добавьте импорты, как в примере ниже:
<!-- calendar.html --> <!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <title>Мой календарь</title> <link rel='stylesheet' href="./style.css"> <!-- стили календаря рекомендую хранить локально --> <link rel='stylesheet' href="./fullcalendar.min.css"> </head> <body> <!-- тут что-то ваше –-> <!-- вот этот блок понадобится, это контейнер для календаря –-> <div id='calendar'></div> <!-- тут что-то ваше –-> <script src='https://cdn.jsdelivr.net/npm/moment@2/min/moment.min.js'></script> <script src='https://cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js'></script> <script src='https://cdn.jsdelivr.net/npm/fullcalendar@3.10.5/dist/fullcalendar.min.js'></script> <!-- подгружаем главный скрипт, который все объединит –-> <script src="./calendar_loader.js"></script> </body> </html>
Далее создайте файл со стилями календаря и копируйте в него стандартный набор. Вместе с этим — заведите файл со скриптом загрузки календаря, он тоже должен быть размещен локально.
// calendar_loader.js $(function() { $('#calendar').fullCalendar({ defaultView: 'agendaWeek', header: { left: 'prev,next today', center: 'title', right: 'agendaWeek,agendaDay' }, // https://fullcalendar.io/docs/events-json-feed events: 'https://fullcalendar.io/api/demo-feeds/events.json' }) });
Отлично! На этом этапе календарь уже отображается, пусть и с тестовым набором данных. Кстати, если у вас в календаре будут другие события, не удивляйтесь: разработчики периодически изменяют содержание тестового файла JSON.
Фронтенд FullCalendar с тестовыми данными.
Шаг 2. Настраиваем отображение
В шаблоне выше я рекомендую хранить fullcalendar.min.css локально. Во-первых, он так будет быстрее загружаться. Во-вторых, мы можем его видоизменять. В этом ничего сложного нет: просто откройте инспектор кода и посмотрите, к каким классам принадлежат элементы вашего календаря. Нужно поменять цвет события? Посмотрите класс в инспекторе — и замените background-color в fullcalendar.min.css. Никакого rocket science.
Шаг 3. Продумайте логику
Если у вас, как и у меня, многопользовательское приложение, продумайте логику: какие есть события, через какую форму пользователи будут их добавлять и так далее. Самый простой из вариантов логики может выглядеть так:
Схема хранения событий и подтягивания данных.
На самом деле, данные можно хранить любым способом. S3-хранилище мне нравится, потому что JSON-структуры сохраняются как объекты. Для меня это довольно удобно, т. к. в перспективе позволяет забыть о базах данных на десятки тысяч строк: пользователей и событий с каждым месяцем может быть все больше.
К тому же объектное хранилище выходит очень дешево, особенно если использовать холодный класс хранения. И последнее преимущество — возможность записи метаданных в объекты. В целом, это киллер-фича, которая позволяет записывать дополнительные сведения о событиях, не ограничиваясь стандартной структурой JSON для работы FullCalendar.
Выбор хранилища зависит от вас и вводных. Например, если есть события, которые встречаются у разных пользователей (это могут быть общие встречи), то такие данные лучше грузить в базу данных. Так получится избежать дублей.
Шаг 4. Реализуйте логику
Рассмотрим на примере предложенной логики.
1. Создайте контейнер объектного хранилища S3. Это можно сделать, например, в облаке Selectel. Для этого перейдите в панель управления my.selectel.ru и откройте раздел Объектное хранилище. Нажмите Создать контейнер, введите его название, выберите тип и класс хранения. Для простоты эксперимента создадим публичный контейнер — не делайте так, если заботитесь о конфиденциальности событий.
Страница создания контейнера в панели управления.
2. Создайте сервисного пользователя в разделе Управление доступом → Сервисные пользователи, нажав на кнопку Добавить пользователя. После сгенерируйте для него S3-ключи — они понадобятся для подключения к объектному хранилищу из бэкенда вашего приложения. Так что сохраните их после получения.
Генерация S3-ключей для сервисного пользователя.
3. Подключитесь к контейнеру из своего приложения и создайте объект с JSON-структурой событий пользователя. Как это сделать с помощью S3-API, рассказали в документации.
# calendar_generator.py # импорт boto3 import boto3 # ключи генерируем в разделе сервисных пользователей # (замените на свои, эти — для примера) access_key = "914866b003e94c569f7b5beb19cb0adf" secret_key = "70232d4de75c4877916d0998db78dbd0" # указываем типовой ендпоинт, название региона, access_key и aws_secret_access_key s3 = boto3.client("s3", endpoint_url="https://s3.ru-1.storage.selcloud.ru", region_name="ru-1", aws_access_key_id=access_key, aws_secret_access_key=secret_key, verify=False) # пользовательские данные (для примера) users_calendars = { 'user_1': { '09.12.24-13.12.24' : '[{"title":"Lunch","start":"2024-12-09T12:00:00+00:00"}]' } } # название контейнера до первой точки # (можно посмотреть в панели управления) bucket_name = 'fullcalendar' # список пользователей и дат users_list = list(users_calendars.keys()) dates_list = list(users_calendars["user_1"].keys()) # название объекта, в который мы запишем данные (наш json-файл) # учтите: если хотите расположить внутри директории, # пропишите ее на уровне названия объекта — она появится key = f'{users_list[0]}/{dates_list[0]}.json' # данные, которые запишем внутрь объекта (тело объекта) body = users_calendars[users_list[0]][dates_list[0]] # загрузка объекта из строки s3.put_object(Bucket=bucket_name, Key=key, Body=body)
Отлично! Мы подгрузили «откуда-то» данные о событиях пользователя user-1 на рабочей неделе с 9 по 13 декабря. Теперь при переходе в S3-хранилище вы увидите директорию и подгруженный объект:
4. Внутри fullcalendar.min.js замените адрес events на уникальную ссылку с событиями пользователя:
// calendar_loader.js $(function() { ... // теперь здесь подгружаем ссылку на объект в s3 // ссылку можно скопировать из панели управления events: 'https://f7f2013c-d34e-4560-99c6-5a60b6d5b291.selstorage.ru/user_1/09.12.24-13.12.24.json' }) });
Готово — все события отображаются в календаре.
При необходимости вы можете его стилизовать и, например, синхронизировать с другими календарями с помощью протокола CalDAV. Но это уже другая история.
ссылка на оригинал статьи https://habr.com/ru/articles/865304/
Добавить комментарий