Модальные окна и notifications

Модальные окна (modals) являются ключевым элементом интерфейсов, обеспечивая контекстное взаимодействие с пользователем без перехода на другие страницы. В SvelteKit их реализация строится на компонентной архитектуре с использованием реактивных переменных и событий.

Создание базового модального окна

Для начала создается компонент Modal.svelte:

<script>
  export let isOpen = false;
  export let title = '';
  export let onCl ose = () => {};
</script>

{#if isOpen}
  <div class="modal-backdrop" on:click="{onClose}"></div>
  <div class="modal">
    <header class="modal-header">
      <h2>{title}</h2>
      <button class="close-button" on:click="{onClose}">&times;</button>
    </header>
    <div class="modal-body">
      <slot></slot>
    </div>
  </div>
{/if}

<style>
  .modal-backdrop {
    position: fixed;
    top: 0; left: 0;
    width: 100%; height: 100%;
    background: rgba(0,0,0,0.5);
  }
  .modal {
    position: fixed;
    top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    background: #fff;
    border-radius: 8px;
    width: 400px;
    max-width: 90%;
    box-shadow: 0 4px 12px rgba(0,0,0,0.3);
  }
  .modal-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 1rem;
    border-bottom: 1px solid #ddd;
  }
  .modal-body {
    padding: 1rem;
  }
  .close-button {
    background: transparent;
    border: none;
    font-size: 1.5rem;
    cursor: pointer;
  }
</style>

Ключевые моменты:

  • isOpen — реактивная переменная, управляющая видимостью модального окна.
  • onClose — callback-функция для закрытия окна.
  • Используется <slot> для вставки динамического контента внутрь модального окна.

Управление состоянием модального окна

В родительском компоненте создается переменная состояния и методы открытия и закрытия:

<script>
  import Modal from './Modal.svelte';
  let showModal = false;

  function openModal() {
    showModal = true;
  }

  function closeModal() {
    showModal = false;
  }
</script>

<button on:click="{openModal}">Открыть модальное окно</button>

<Modal isOpen="{showModal}" title="Пример модального окна" onCl ose="{closeModal}">
  <p>Содержимое модального окна можно менять динамически.</p>
</Modal>

Использование реактивного состояния showModal обеспечивает синхронизацию UI с внутренней логикой приложения без сторонних библиотек управления состоянием.


Notifications и Toasts

Уведомления (notifications) и всплывающие подсказки (toasts) служат для краткого информирования пользователя о результатах действий или событиях системы. В SvelteKit их удобно реализовать с помощью store и компонентной системы.

Создание store для уведомлений

// notifications.js
import { writable } from 'svelte/store';

export const notifications = writable([]);

export function addNotification({ message, type = 'info', duration = 3000 }) {
  const id = Date.now();
  notifications.update(n => [...n, { id, message, type }]);
  setTimeout(() => removeNotification(id), duration);
}

export function removeNotification(id) {
  notifications.update(n => n.filter(notification => notification.id !== id));
}

Особенности:

  • Использование writable store позволяет реактивно отображать список уведомлений.
  • Каждое уведомление имеет уникальный id, что упрощает удаление.
  • duration задает автоматическое скрытие уведомления через заданное время.

Компонент Notifications

<script>
  import { notifications, removeNotification } from './notifications.js';
  import { fly } from 'svelte/transition';
</script>

<div class="notifications-container">
  {#each $notifications as notif (notif.id)}
    <div class="notification {notif.type}" transition:fly="{{ y: -20, duration: 300 }}">
      <span>{notif.message}</span>
      <button class="close" on:click="{() => removeNotification(notif.id)}">&times;</button>
    </div>
  {/each}
</div>

<style>
  .notifications-container {
    position: fixed;
    top: 1rem;
    right: 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    z-index: 1000;
  }
  .notification {
    padding: 0.75rem 1rem;
    border-radius: 6px;
    color: #fff;
    display: flex;
    justify-content: space-between;
    align-items: center;
    box-shadow: 0 2px 8px rgba(0,0,0,0.2);
  }
  .notification.info { background: #3498db; }
  .notification.success { background: #2ecc71; }
  .notification.warning { background: #f1c40f; color: #000; }
  .notification.error { background: #e74c3c; }
  .close {
    background: transparent;
    border: none;
    font-size: 1rem;
    cursor: pointer;
    color: inherit;
  }
</style>

Использование Notifications в приложении

<script>
  import { addNotification } from './notifications.js';

  function showSuccess() {
    addNotification({ message: 'Данные успешно сохранены', type: 'success' });
  }

  function showError() {
    addNotification({ message: 'Ошибка при сохранении', type: 'error' });
  }
</script>

<button on:click="{showSuccess}">Показать успех</button>
<button on:click="{showError}">Показать ошибку</button>

Преимущества такой архитектуры:

  • Уведомления полностью реактивны и управляются через store.
  • Легко масштабируются: добавление новых типов уведомлений или глобальная настройка duration не требует изменения компонентов.
  • Механизм transition позволяет добавлять плавные анимации появления и исчезновения.

Интеграция модальных окон с notifications

Модальные окна и уведомления часто работают совместно. Например, при подтверждении действия в модальном окне можно сразу показывать уведомление:

<Modal isOpen="{showModal}" title="Удаление элемента" onCl ose="{closeModal}">
  <p>Вы действительно хотите удалить этот элемент?</p>
  <button on:click="{() => { deleteItem(); addNotification({ message: 'Элемент удален', type: 'success' }); closeModal(); }}">
    Подтвердить
  </button>
</Modal>

Ключевые моменты интеграции:

  • События внутри модального окна могут вызывать store уведомлений.
  • Сохранение реактивного состояния isOpen предотвращает утечку событий и обеспечивает правильное управление UI.
  • Использование компонентной архитектуры позволяет повторно применять модальные окна и уведомления в любом месте приложения.

Анимации и кастомизация

SvelteKit предоставляет встроенные transition и animate функции, которые легко интегрируются с модальными окнами и уведомлениями:

<div class="modal" transition:fade="{{ duration: 250 }}">
  • fade, fly, slide — стандартные эффекты, которые можно комбинировать.
  • Пользовательские анимации создаются через функцию tweened или spring.
  • В сочетании с slot и store это обеспечивает гибкость и масштабируемость интерфейса.

Модальные окна и notifications в SvelteKit строятся вокруг реактивных переменных, store и компонентного подхода, что обеспечивает простоту управления состоянием, легкость интеграции и масштабируемость UI.