diff --git a/SECURE-T_Documentation.md b/SECURE-T_Documentation.md deleted file mode 100644 index bdc67a3..0000000 --- a/SECURE-T_Documentation.md +++ /dev/null @@ -1,491 +0,0 @@ -# SECURE-T - Документация - -## Содержание -1. [Обзор системы](#обзор-системы) -2. [Основные решения](#основные-решения) -3. [Технологии](#технологии) -4. [Архитектура](#архитектура) -5. [Установка и настройка](#установка-и-настройка) -6. [Руководство пользователя](#руководство-пользователя) -7. [API документация](#api-документация) -8. [Безопасность](#безопасность) -9. [Поддержка](#поддержка) - ---- - -## Обзор системы - -**SECURE-T** — это комплексная система информационной безопасности, разработанная для защиты корпоративных данных и IT-инфраструктуры от современных киберугроз. - -### Основные преимущества -- ✅ Комплексная защита данных -- ✅ Современные криптографические алгоритмы -- ✅ Интеграция с существующей инфраструктурой -- ✅ Централизованное управление безопасностью -- ✅ Соответствие российским и международным стандартам - -### Целевая аудитория -- Крупные корпорации -- Государственные учреждения -- Финансовые организации -- Медицинские учреждения -- Образовательные институты - ---- - -## Основные решения - -### 🔐 Криптографическая защита -Обеспечивает надежное шифрование данных с использованием современных алгоритмов. - -**Возможности:** -- Шифрование файлов и баз данных -- Защита каналов связи -- Цифровая подпись документов -- Управление ключами шифрования - -**Поддерживаемые алгоритмы:** -- AES-256 (симметричное шифрование) -- RSA-4096 (асимметричное шифрование) -- SHA-3 (хеширование) - -### 🛡️ Сетевая безопасность -Комплексная защита сетевой инфраструктуры от внешних и внутренних угроз. - -**Компоненты:** -- Межсетевые экраны (Firewall) -- Системы обнаружения вторжений (IDS/IPS) -- Веб-защита (WAF) -- VPN-шлюзы - -**Функции:** -- Фильтрация трафика -- Блокировка вредоносных соединений -- Мониторинг сетевой активности -- Защита от DDoS-атак - -### 📊 Мониторинг безопасности -Система непрерывного мониторинга и анализа событий безопасности. - -**Возможности:** -- Сбор и анализ журналов событий -- Корреляция инцидентов -- Автоматическое реагирование на угрозы -- Генерация отчетов о безопасности - -**Интеграция с SIEM:** -- Централизованный сбор данных -- Анализ в реальном времени -- Настраиваемые правила корреляции -- Панель управления безопасностью - -### 🔍 Аудит безопасности -Проведение комплексного анализа систем информационной безопасности. - -**Виды аудита:** -- Технический аудит инфраструктуры -- Аудит соответствия стандартам -- Анализ уязвимостей -- Оценка рисков информационной безопасности - -### ⚙️ Интеграция систем -Бесшовная интеграция с существующей IT-инфраструктурой. - -**Поддерживаемые системы:** -- Active Directory -- LDAP -- Oracle Database -- Microsoft SQL Server -- VMware vCenter -- Cisco Network Equipment - -### 📚 Обучение персонала -Комплексные программы повышения квалификации в области информационной безопасности. - -**Программы обучения:** -- Основы информационной безопасности -- Работа с системами SECURE-T -- Реагирование на инциденты -- Администрирование систем безопасности - ---- - -## Технологии - -### Криптографические технологии -| Технология | Назначение | Стандарт | -|------------|------------|----------| -| **AES-256** | Симметричное шифрование данных | FIPS 197 | -| **RSA-4096** | Асимметричное шифрование | PKCS #1 | -| **SHA-3** | Криптографическое хеширование | FIPS 202 | -| **PKI** | Инфраструктура открытых ключей | RFC 5280 | - -### Системы безопасности -| Технология | Описание | -|------------|----------| -| **SIEM** | Управление информацией и событиями безопасности | -| **DLP** | Предотвращение утечек данных | -| **WAF** | Веб-защита приложений | -| **IDS/IPS** | Обнаружение и предотвращение вторжений | - ---- - -## Архитектура - -### Архитектурная схема -``` -┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ -│ Пользователи │ │ Приложения │ │ Данные │ -└─────────┬───────┘ └─────────┬───────┘ └─────────┬───────┘ - │ │ │ - ▼ ▼ ▼ -┌─────────────────────────────────────────────────────────────────┐ -│ SECURE-T Platform │ -├─────────────────┬─────────────────┬─────────────────────────────┤ -│ Аутентификация │ Авторизация │ Аудит │ -├─────────────────┼─────────────────┼─────────────────────────────┤ -│ Шифрование │ Мониторинг │ Управление │ -└─────────────────┴─────────────────┴─────────────────────────────┘ -``` - -### Компоненты системы - -#### Центр управления безопасностью (SOC) -- Централизованная консоль управления -- Мониторинг в реальном времени -- Управление инцидентами -- Отчетность и аналитика - -#### Модуль криптографической защиты -- Управление ключами шифрования -- Шифрование/дешифрование данных -- Цифровая подпись -- Проверка целостности - -#### Сетевой модуль безопасности -- Межсетевые экраны -- Системы обнаружения вторжений -- VPN-шлюзы -- Анализ трафика - ---- - -## Установка и настройка - -### Системные требования - -#### Минимальные требования -- **ОС:** Windows Server 2019/2022, Linux (Ubuntu 20.04+, CentOS 8+) -- **Процессор:** Intel Xeon E5-2600 v4 или аналогичный -- **ОЗУ:** 16 GB -- **Дисковое пространство:** 500 GB SSD -- **Сеть:** Gigabit Ethernet - -#### Рекомендуемые требования -- **Процессор:** Intel Xeon Gold 6200 или аналогичный -- **ОЗУ:** 64 GB -- **Дисковое пространство:** 2 TB NVMe SSD -- **Сеть:** 10 Gigabit Ethernet - -### Процедура установки - -#### 1. Подготовка инфраструктуры -```bash -# Обновление системы -sudo apt update && sudo apt upgrade -y - -# Установка зависимостей -sudo apt install -y docker.io docker-compose postgresql-client -``` - -#### 2. Установка SECURE-T -```bash -# Загрузка установочного пакета -wget https://releases.secure-t.com/latest/secure-t-installer.tar.gz - -# Распаковка -tar -xzf secure-t-installer.tar.gz - -# Запуск установки -sudo ./install.sh -``` - -#### 3. Первоначальная настройка -```bash -# Инициализация базы данных -secure-t-admin init-db - -# Создание администратора -secure-t-admin create-admin --username admin --password - -# Запуск сервисов -systemctl start secure-t -systemctl enable secure-t -``` - -### Конфигурация - -#### Основной файл конфигурации -```yaml -# /etc/secure-t/config.yaml -server: - host: "0.0.0.0" - port: 8443 - ssl: - enabled: true - cert_file: "/etc/secure-t/ssl/server.crt" - key_file: "/etc/secure-t/ssl/server.key" - -database: - type: "postgresql" - host: "localhost" - port: 5432 - name: "secure_t" - username: "secure_t_user" - password: "secure_password" - -crypto: - default_algorithm: "AES-256-GCM" - key_derivation: "PBKDF2" - hash_algorithm: "SHA-3-256" - -logging: - level: "INFO" - file: "/var/log/secure-t/secure-t.log" - max_size: "100MB" - max_files: 10 -``` - ---- - -## Руководство пользователя - -### Веб-интерфейс - -#### Вход в систему -1. Откройте браузер и перейдите по адресу: `https://your-server:8443` -2. Введите логин и пароль -3. Пройдите двухфакторную аутентификацию (если настроена) - -#### Главная панель управления -- **Дашборд** - общая информация о состоянии безопасности -- **События** - журнал событий безопасности -- **Политики** - настройка политик безопасности -- **Пользователи** - управление пользователями и ролями -- **Отчеты** - генерация отчетов - -### Основные операции - -#### Создание политики шифрования -1. Перейдите в раздел "Политики" -2. Нажмите "Создать новую политику" -3. Выберите тип данных для шифрования -4. Настройте параметры шифрования -5. Примените политику к нужным ресурсам - -#### Мониторинг событий -1. Откройте раздел "События" -2. Используйте фильтры для поиска нужных событий -3. Просмотрите детали события -4. При необходимости создайте инцидент - -#### Управление пользователями -1. Перейдите в раздел "Пользователи" -2. Добавьте нового пользователя -3. Назначьте роли и права доступа -4. Настройте двухфакторную аутентификацию - ---- - -## API документация - -### Аутентификация - -Все API запросы должны содержать токен аутентификации в заголовке: -``` -Authorization: Bearer -``` - -### Получение токена -```http -POST /api/v1/auth/login -Content-Type: application/json - -{ - "username": "admin", - "password": "password" -} -``` - -**Ответ:** -```json -{ - "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", - "expires_in": 3600 -} -``` - -### Основные эндпоинты - -#### Управление пользователями -```http -GET /api/v1/users -POST /api/v1/users -PUT /api/v1/users/{id} -DELETE /api/v1/users/{id} -``` - -#### События безопасности -```http -GET /api/v1/events -GET /api/v1/events/{id} -POST /api/v1/events/search -``` - -#### Политики безопасности -```http -GET /api/v1/policies -POST /api/v1/policies -PUT /api/v1/policies/{id} -DELETE /api/v1/policies/{id} -``` - -### Примеры использования - -#### Получение списка событий -```bash -curl -X GET \ - https://your-server:8443/api/v1/events \ - -H 'Authorization: Bearer ' \ - -H 'Content-Type: application/json' -``` - -#### Создание нового пользователя -```bash -curl -X POST \ - https://your-server:8443/api/v1/users \ - -H 'Authorization: Bearer ' \ - -H 'Content-Type: application/json' \ - -d '{ - "username": "newuser", - "email": "user@example.com", - "role": "operator" - }' -``` - ---- - -## Безопасность - -### Рекомендации по безопасности - -#### Настройка SSL/TLS -- Используйте только TLS 1.2 или выше -- Настройте сильные шифры -- Регулярно обновляйте SSL-сертификаты - -#### Управление паролями -- Минимальная длина пароля: 12 символов -- Обязательное использование спецсимволов -- Регулярная смена паролей (каждые 90 дней) -- Запрет на повторное использование последних 12 паролей - -#### Двухфакторная аутентификация -- Обязательна для всех администраторов -- Поддержка TOTP (Google Authenticator, Authy) -- Резервные коды для восстановления доступа - -#### Аудит и мониторинг -- Включите детальное логирование всех операций -- Настройте автоматические уведомления о критических событиях -- Регулярно проводите анализ журналов безопасности - -### Соответствие стандартам - -SECURE-T соответствует следующим стандартам: -- **ГОСТ Р 57580.1-2017** - Безопасность финансовых услуг -- **ISO 27001** - Системы менеджмента информационной безопасности -- **NIST Cybersecurity Framework** - Основы кибербезопасности -- **PCI DSS** - Стандарт безопасности данных платежных карт - ---- - -## Поддержка - -### Техническая поддержка - -#### Контактная информация -- **Email:** support@secure-t.com -- **Телефон:** +7 (495) 123-45-67 -- **Время работы:** 24/7 - -#### Уровни поддержки -- **Критический** - отклик в течение 1 часа -- **Высокий** - отклик в течение 4 часов -- **Средний** - отклик в течение 8 часов -- **Низкий** - отклик в течение 24 часов - -### Обновления и патчи - -#### Автоматические обновления -```bash -# Включение автоматических обновлений -secure-t-admin config set auto-update enabled - -# Настройка расписания обновлений -secure-t-admin config set update-schedule "0 2 * * 0" -``` - -#### Ручные обновления -```bash -# Проверка доступных обновлений -secure-t-admin update check - -# Установка обновлений -secure-t-admin update install - -# Откат к предыдущей версии -secure-t-admin update rollback -``` - -### Документация и ресурсы - -#### Дополнительные материалы -- 📄 **Техническая документация** - подробные руководства по настройке -- 🎯 **Методические материалы** - лучшие практики безопасности -- 🔧 **Инструменты настройки** - утилиты для конфигурирования -- 📊 **Отчеты и аналитика** - шаблоны отчетов -- 🎓 **Обучающие материалы** - курсы и тренинги -- 📋 **Сертификаты и лицензии** - документы о соответствии - -#### Полезные ссылки -- [Официальный сайт](https://secure-t.com) -- [База знаний](https://kb.secure-t.com) -- [Форум сообщества](https://community.secure-t.com) -- [GitHub репозиторий](https://github.com/secure-t/secure-t) - ---- - -## Приложения - -### Приложение A: Коды ошибок -| Код | Описание | Решение | -|-----|----------|---------| -| ST-001 | Ошибка аутентификации | Проверьте логин и пароль | -| ST-002 | Недостаточно прав | Обратитесь к администратору | -| ST-003 | Ошибка шифрования | Проверьте настройки криптографии | -| ST-004 | Сетевая ошибка | Проверьте сетевые подключения | - -### Приложение B: Глоссарий -- **AES** - Advanced Encryption Standard, стандарт шифрования -- **DLP** - Data Loss Prevention, предотвращение утечек данных -- **IDS/IPS** - Intrusion Detection/Prevention System -- **PKI** - Public Key Infrastructure, инфраструктура открытых ключей -- **SIEM** - Security Information and Event Management -- **WAF** - Web Application Firewall, веб-защита приложений - ---- - -*Документация SECURE-T версия 1.0* -*Последнее обновление: 2024* -*© GUNDYREV. Все права защищены.* \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 023c4fc..39880dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,20 +8,32 @@ "name": "my-app", "version": "0.1.0", "dependencies": { + "@radix-ui/react-avatar": "^1.1.10", + "@radix-ui/react-dialog": "^1.1.14", + "@radix-ui/react-label": "^2.1.7", + "@radix-ui/react-navigation-menu": "^1.2.13", + "@radix-ui/react-progress": "^1.1.7", + "@radix-ui/react-select": "^2.2.5", + "@radix-ui/react-separator": "^1.1.7", + "@radix-ui/react-slot": "^1.2.3", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", "geist": "^1.4.2", + "lucide-react": "^0.525.0", "next": "15.3.4", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "tailwind-merge": "^3.3.1" }, "devDependencies": { "@eslint/eslintrc": "^3", - "@tailwindcss/postcss": "^4", + "@tailwindcss/postcss": "^4.1.11", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", "eslint": "^9", "eslint-config-next": "15.3.4", - "tailwindcss": "^4", + "tw-animate-css": "^1.3.5", "typescript": "^5" } }, @@ -239,6 +251,44 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.2.tgz", + "integrity": "sha512-wNB5ooIKHQc+Kui96jE/n69rHFWAVoxn5CAzL1Xdd8FG03cgY3MLO+GF9U3W737fYDSgPWA6MReKhBQBop6Pcw==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.2.tgz", + "integrity": "sha512-7cfaOQuCS27HD7DX+6ib2OrnW+b4ZBwDNnCcT0uTyidcmyWb03FnQqJybDBoCnpdxwBSfA94UAYlRCt7mV+TbA==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.2", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.4.tgz", + "integrity": "sha512-JbbpPhp38UmXDDAu60RJmbeme37Jbgsm7NrHGgzYYFKmblzRUh6Pa641dII6LsjwF4XlScDrde2UAzDo/b9KPw==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.2" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -972,6 +1022,713 @@ "node": ">=12.4.0" } }, + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz", + "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-avatar": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.10.tgz", + "integrity": "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.14.tgz", + "integrity": "sha512-+CpweKjqpzTmwRwcYECQcNYbI8V9VSQt0SNFKeEBLgfucbsLssU6Ppq7wUdNXEGb573bMjFhVjKVll8rmV6zMw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.10", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz", + "integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz", + "integrity": "sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.7.tgz", + "integrity": "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-navigation-menu": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.13.tgz", + "integrity": "sha512-WG8wWfDiJlSF5hELjwfjSGOXcBR/ZMhBFCGYe8vERpC39CQYZeq1PQ2kaYHdye3V95d06H89KGMsVCIE4LWo3g==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.10", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.7.tgz", + "integrity": "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz", + "integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.7.tgz", + "integrity": "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-select": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.5.tgz", + "integrity": "sha512-HnMTdXEVuuyzx63ME0ut4+sEMYW6oouHWNGUZc7ddvUWIcfCva/AMoqEW/3wnEllriMWBa0RHspCYnfCWJQYmA==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.10", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.7", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-separator": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.7.tgz", + "integrity": "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz", + "integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "license": "MIT" + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -1323,7 +2080,7 @@ "version": "19.1.8", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz", "integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "csstype": "^3.0.2" @@ -1333,7 +2090,7 @@ "version": "19.1.6", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.6.tgz", "integrity": "sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "@types/react": "^19.0.0" @@ -1958,6 +2715,18 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/aria-query": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", @@ -2330,12 +3099,33 @@ "node": ">=18" } }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", "license": "MIT" }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/color": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", @@ -2407,7 +3197,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/damerau-levenshtein": { @@ -2542,6 +3332,12 @@ "node": ">=8" } }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, "node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -3423,6 +4219,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/get-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", @@ -4523,6 +5328,15 @@ "loose-envify": "cli.js" } }, + "node_modules/lucide-react": { + "version": "0.525.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.525.0.tgz", + "integrity": "sha512-Tm1txJ2OkymCGkvwoHt33Y2JpN5xucVq1slHcgE6Lk0WjDfjgKWor5CdVER8U6DvcfMwh4M8XxmpTiyzfmfDYQ==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/magic-string": { "version": "0.30.17", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", @@ -5129,6 +5943,75 @@ "dev": true, "license": "MIT" }, + "node_modules/react-remove-scroll": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz", + "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -5746,6 +6629,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tailwind-merge": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz", + "integrity": "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, "node_modules/tailwindcss": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.11.tgz", @@ -5871,6 +6764,16 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/tw-animate-css": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.3.5.tgz", + "integrity": "sha512-t3u+0YNoloIhj1mMXs779P6MO9q3p3mvGn4k1n3nJPqJw/glZcuijG2qTSN4z4mgNRfW5ZC3aXJFLwDtiipZXA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Wombosvideo" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -6047,6 +6950,58 @@ "punycode": "^2.1.0" } }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz", + "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 287e24c..ff8b529 100644 --- a/package.json +++ b/package.json @@ -9,20 +9,32 @@ "lint": "next lint" }, "dependencies": { + "@radix-ui/react-avatar": "^1.1.10", + "@radix-ui/react-dialog": "^1.1.14", + "@radix-ui/react-label": "^2.1.7", + "@radix-ui/react-navigation-menu": "^1.2.13", + "@radix-ui/react-progress": "^1.1.7", + "@radix-ui/react-select": "^2.2.5", + "@radix-ui/react-separator": "^1.1.7", + "@radix-ui/react-slot": "^1.2.3", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", "geist": "^1.4.2", + "lucide-react": "^0.525.0", "next": "15.3.4", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "tailwind-merge": "^3.3.1" }, "devDependencies": { "@eslint/eslintrc": "^3", - "@tailwindcss/postcss": "^4", + "@tailwindcss/postcss": "^4.1.11", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", "eslint": "^9", "eslint-config-next": "15.3.4", - "tailwindcss": "^4", + "tw-animate-css": "^1.3.5", "typescript": "^5" } } diff --git a/secure-t-project.zip b/secure-t-project.zip deleted file mode 100644 index 92dfa7b..0000000 Binary files a/secure-t-project.zip and /dev/null differ diff --git a/src/app/components/ContactModal.tsx b/src/app/components/ContactModal.tsx index 69fda0c..3283f04 100644 --- a/src/app/components/ContactModal.tsx +++ b/src/app/components/ContactModal.tsx @@ -1,28 +1,42 @@ 'use client'; -import { useState } from 'react'; +import { useState, useEffect } from 'react'; +import { + MessageCircle, + Briefcase, + Settings, + Lightbulb, + Phone, + Mail, + X +} from 'lucide-react'; -interface ContactModalProps { +export interface ContactModalProps { isOpen: boolean; onClose: () => void; defaultType?: string; title?: string; } -export default function ContactModal({ - isOpen, - onClose, - defaultType = 'general', - title = 'Связаться с нами' -}: ContactModalProps) { +export default function ContactModal({ isOpen, onClose, defaultType = 'general', title = 'Связаться с нами' }: ContactModalProps) { const [formData, setFormData] = useState({ name: '', email: '', phone: '', company: '', - message: '', - type: defaultType + type: defaultType, + message: '' }); + const [isSubmitting, setIsSubmitting] = useState(false); + const [submitStatus, setSubmitStatus] = useState<'idle' | 'success' | 'error'>('idle'); + + const contactTypes = [ + { id: 'general', label: 'Общие вопросы', icon: }, + { id: 'sales', label: 'Отдел продаж', icon: }, + { id: 'support', label: 'Техподдержка', icon: }, + { id: 'development', label: 'Разработка', icon: }, + { id: 'consultation', label: 'Консультация', icon: }, + ]; const handleInputChange = (e: React.ChangeEvent) => { const { name, value } = e.target; @@ -39,15 +53,6 @@ export default function ContactModal({ onClose(); }; - const contactTypes = [ - { id: 'general', label: 'Общие вопросы', icon: '💬' }, - { id: 'sales', label: 'Отдел продаж', icon: '💼' }, - { id: 'support', label: 'Техподдержка', icon: '🔧' }, - { id: 'partnership', label: 'Партнёрство', icon: '🤝' }, - { id: 'consultation', label: 'Консультация', icon: '💡' }, - { id: 'demo', label: 'Демонстрация', icon: '🖥️' } - ]; - if (!isOpen) return null; return ( @@ -173,9 +178,9 @@ export default function ContactModal({

Или свяжитесь с нами напрямую:
- 📞 +7 (495) 123-45-67 + +7 (495) 123-45-67
- 📧 info@gundyrev.ru + info@gundyrev.ru

diff --git a/src/app/components/FloatingCTA.tsx b/src/app/components/FloatingCTA.tsx index 43aef7f..64aa597 100644 --- a/src/app/components/FloatingCTA.tsx +++ b/src/app/components/FloatingCTA.tsx @@ -1,6 +1,7 @@ 'use client'; import { useState, useEffect } from 'react'; +import { Phone, Lightbulb } from 'lucide-react'; import ContactModal from './ContactModal'; export default function FloatingCTA() { @@ -44,9 +45,7 @@ export default function FloatingCTA() { }} >
- - 📞 - + {ctaTexts[currentText]} @@ -66,7 +65,8 @@ export default function FloatingCTA() { className="block w-full px-4 py-2 bg-blue-500 text-white text-sm rounded-lg hover:bg-blue-600 transition-colors duration-200" title="Заказать консультацию" > - 💡 Консультация + + Консультация {/* Улучшенный переключатель темы */} @@ -126,20 +137,16 @@ export default function Navigation() { aria-label="Переключить тему" title={theme === 'dark' ? 'Переключить на светлую тему' : 'Переключить на тёмную тему'} > - - 🌙 - - + - ☀️ - + />
@@ -151,7 +158,7 @@ export default function Navigation() { onClick={() => setIsContactModalOpen(true)} className="bg-gradient-to-r from-green-500 to-emerald-500 text-white px-3 py-1.5 rounded-md font-medium text-xs hover:from-green-600 hover:to-emerald-600 transition-all duration-200" > - 📞 + {/* Мобильный переключатель темы */} @@ -161,20 +168,16 @@ export default function Navigation() { aria-label="Переключить тему" title={theme === 'dark' ? 'Переключить на светлую тему' : 'Переключить на тёмную тему'} > - - 🌙 - - + - ☀️ - + /> diff --git a/src/app/globals.css b/src/app/globals.css index bcd5059..dfb95c7 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,9 +1,10 @@ @import "tailwindcss"; +@import "tw-animate-css"; + +@custom-variant dark (&:is(.dark *)); :root { - --background: #0a0a0a; - --foreground: #ffffff; - --accent: #00ff88; + --accent: oklch(0.97 0 0); --gray: #333333; --light-gray: #666666; --glass-bg: rgba(255, 255, 255, 0.05); @@ -12,6 +13,37 @@ --text-primary: #ffffff; --text-secondary: #d1d5db; --text-muted: #9ca3af; + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); } .light { @@ -42,11 +74,41 @@ --color-light-gray: var(--light-gray); --font-sans: var(--font-geist-sans); --font-mono: var(--font-geist-mono); + --color-sidebar-ring: var(--sidebar-ring); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar: var(--sidebar); + --color-chart-5: var(--chart-5); + --color-chart-4: var(--chart-4); + --color-chart-3: var(--chart-3); + --color-chart-2: var(--chart-2); + --color-chart-1: var(--chart-1); + --color-ring: var(--ring); + --color-input: var(--input); + --color-border: var(--border); + --color-destructive: var(--destructive); + --color-accent-foreground: var(--accent-foreground); + --color-muted-foreground: var(--muted-foreground); + --color-muted: var(--muted); + --color-secondary-foreground: var(--secondary-foreground); + --color-secondary: var(--secondary); + --color-primary-foreground: var(--primary-foreground); + --color-primary: var(--primary); + --color-popover-foreground: var(--popover-foreground); + --color-popover: var(--popover); + --color-card-foreground: var(--card-foreground); + --color-card: var(--card); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); } body { - background: var(--background); - color: var(--foreground); font-family: var(--font-sans), Arial, Helvetica, sans-serif; line-height: 1.6; overflow-x: hidden; @@ -663,29 +725,29 @@ body { .section-padding { padding: 40px 0; } - + .draggable-card { width: 280px !important; } - + .glass-effect { backdrop-filter: blur(5px); } - + .holographic-text { text-shadow: 0 0 5px rgba(0, 255, 136, 0.3), 0 0 10px rgba(0, 255, 136, 0.2); } - + .animate-spin-slow { animation-duration: 30s; } - + .animate-spin-reverse { animation-duration: 25s; } - + .tech-sphere-item { font-size: 0.75rem; padding: 0.25rem 0.5rem; @@ -697,7 +759,7 @@ body { .hover-glow:hover { box-shadow: none; } - + .draggable-card:active { transform: scale(0.95); } @@ -712,7 +774,7 @@ body { .tech-sphere-item { animation: none; } - + .hover-lift:hover { transform: none; } @@ -2198,4 +2260,47 @@ body { box-shadow: 0 6px 24px rgba(102, 126, 234, 0.15), 0 3px 12px rgba(0, 0, 0, 0.08) !important; +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } } \ No newline at end of file diff --git a/src/app/page.tsx b/src/app/page.tsx index 60f2a5f..b6ca0b3 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,10 +1,33 @@ 'use client'; import { useState, useEffect } from 'react'; +import { + Rocket, + Lightbulb, + BarChart3, + Palette, + Settings, + Database, + Zap, + Building, + GraduationCap, + Hospital, + Landmark, + DollarSign, + Factory, + Cpu, + Star, + ClipboardList, + Trophy, + Shield, + Briefcase, + Mail, + Phone, + MessageCircle +} from 'lucide-react'; import Navigation from './components/Navigation'; import InteractiveBlocks from './components/InteractiveBlocks'; import ContactModal from './components/ContactModal'; -import Footer from './components/Footer'; export default function Home() { const [mounted, setMounted] = useState(false); @@ -228,21 +251,24 @@ model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')`
@@ -292,28 +318,28 @@ model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')` {[ { category: 'Frontend', - icon: '🎨', + icon: , color: 'from-purple-500 to-pink-500', techs: ['React', 'Next.js', 'Vue.js', 'TypeScript', 'Tailwind CSS'], description: 'Современные пользовательские интерфейсы' }, { category: 'Backend', - icon: '⚙️', + icon: , color: 'from-blue-500 to-cyan-500', techs: ['Node.js', 'Python', 'Express', 'FastAPI', 'GraphQL'], description: 'Мощные серверные решения' }, { category: 'Database', - icon: '🗄️', + icon: , color: 'from-green-500 to-emerald-500', techs: ['PostgreSQL', 'MongoDB', 'Redis', 'MySQL', 'Elasticsearch'], description: 'Надежное хранение данных' }, { category: 'DevOps', - icon: '🚀', + icon: , color: 'from-orange-500 to-red-500', techs: ['Docker', 'Kubernetes', 'AWS', 'Jenkins', 'Terraform'], description: 'Автоматизация и развертывание' @@ -326,7 +352,7 @@ model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')` animationDelay: `${categoryIndex * 0.2}s` }} > -
+
{category.icon}
@@ -522,21 +548,30 @@ model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')`
-

🚀 Современные технологии

+

+ + Современные технологии +

Используем последние версии фреймворков и библиотек для создания производительных приложений

-

🔧 Чистый код

+

+ + Чистый код +

Следуем принципам SOLID, используем TypeScript и покрываем код тестами

-

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

+

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

Оптимизируем каждую строчку кода для максимальной скорости работы

@@ -600,6 +635,396 @@ model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')`
+ {/* Our Clients Section */} +
+
+
+

Наши клиенты

+

+ Нам доверяют ведущие организации и компании России +

+
+ + {/* Client Statistics */} +
+
+
+ +
+
15+
+
Госорганы
+
+ +
+
+ +
+
30+
+
Коммерческие организации
+
+ +
+
+ +
+
8+
+
Образовательные учреждения
+
+ +
+
+ +
+
12+
+
Медицинские организации
+
+
+ + {/* Client Types Showcase */} +
+ {[ + { + category: 'Государственные структуры', + icon: , + description: 'Министерства, ведомства, муниципальные образования', + examples: ['Администрации регионов', 'Министерства', 'Муниципальные учреждения'], + color: 'from-blue-500 to-indigo-600', + projects: '25+ проектов' + }, + { + category: 'Финансовые организации', + icon: , + description: 'Банки, страховые компании, инвестиционные фонды', + examples: ['Региональные банки', 'Страховые компании', 'Микрофинансовые организации'], + color: 'from-green-500 to-emerald-600', + projects: '18+ проектов' + }, + { + category: 'Производственные предприятия', + icon: , + description: 'Промышленные компании и производители', + examples: ['Машиностроительные заводы', 'Пищевые производства', 'Текстильные фабрики'], + color: 'from-orange-500 to-red-600', + projects: '22+ проектов' + }, + { + category: 'IT и Телеком', + icon: , + description: 'Технологические компании и операторы связи', + examples: ['IT-интеграторы', 'Провайдеры связи', 'Разработчики ПО'], + color: 'from-purple-500 to-pink-600', + projects: '15+ проектов' + }, + { + category: 'Образование и наука', + icon: , + description: 'Университеты, школы, научные институты', + examples: ['Высшие учебные заведения', 'Школы и лицеи', 'НИИ и лаборатории'], + color: 'from-cyan-500 to-blue-600', + projects: '12+ проектов' + }, + { + category: 'Медицина и здравоохранение', + icon: , + description: 'Больницы, клиники, медицинские центры', + examples: ['Региональные больницы', 'Частные клиники', 'Диагностические центры'], + color: 'from-teal-500 to-green-600', + projects: '14+ проектов' + } + ].map((clientType, index) => ( +
+
+ {clientType.icon} +
+ +

{clientType.category}

+

{clientType.description}

+ +
+ {clientType.examples.map((example, exampleIndex) => ( +
+ + {example} +
+ ))} +
+ +
+ {clientType.projects} +
+
+ ))} +
+ + {/* Client Testimonials */} +
+

Отзывы клиентов

+ +
+ {[ + { + text: "Команда GUNDYREV профессионально подошла к решению наших задач по автоматизации документооборота. Проект выполнен качественно и в срок.", + author: "Александр Петров", + position: "Начальник IT-отдела", + company: "Администрация г. Вологда", + rating: 5 + }, + { + text: "Отличная работа по поставке серверного оборудования. Все требования 44-ФЗ соблюдены, документооборот организован четко.", + author: "Мария Сидорова", + position: "Заместитель директора", + company: "ГБУЗ ВО \"Областная больница\"", + rating: 5 + }, + { + text: "Разработали для нас комплексную систему управления производством. Результат превзошел ожидания, ROI достигнут за 8 месяцев.", + author: "Дмитрий Козлов", + position: "Технический директор", + company: "ООО \"ВологдаМаш\"", + rating: 5 + } + ].map((testimonial, index) => ( +
+
+ {[...Array(testimonial.rating)].map((_, i) => ( + + ))} +
+ +

“{testimonial.text}”

+ +
+
{testimonial.author}
+
{testimonial.position}
+
{testimonial.company}
+
+
+ ))} +
+
+ + {/* Why Choose Us for Clients */} +
+

Почему нас выбирают

+ +
+ {[ + { + icon: , + title: 'Работа по 44-ФЗ и 223-ФЗ', + description: 'Полное соблюдение требований государственных закупок' + }, + { + icon: , + title: 'Высокое качество', + description: '98% проектов сдаются с первого раза без доработок' + }, + { + icon: , + title: 'Быстрая реализация', + description: 'Средний срок проекта на 30% меньше рыночного' + }, + { + icon: , + title: 'Гарантии и поддержка', + description: 'Расширенная гарантия и техподдержка 24/7' + } + ].map((advantage, index) => ( +
+
{advantage.icon}
+

{advantage.title}

+

{advantage.description}

+
+ ))} +
+
+ + {/* CTA for Potential Clients */} +
+

Хотите стать нашим клиентом?

+

+ Присоединяйтесь к числу довольных клиентов GUNDYREV. Мы готовы обсудить ваш проект и предложить оптимальное решение. +

+ +
+ + +
+
+
+
+ + {/* Government Procurement Section */} +
+
+
+

+ Работаем с госзакупками +

+

+ Профессиональное участие в государственных и корпоративных закупках. + Соответствуем всем требованиям 44-ФЗ и 223-ФЗ. +

+ + {/* Яркие бейджи для снабженцев */} +
+
+ 44-ФЗ + Госзакупки +
+
+ 223-ФЗ + Корпоративные закупки +
+
+ Реестр ОПО + Отечественное ПО +
+
+
+ +
+ {[ + { + title: 'IT-решения', + description: 'Разработка и поставка программного обеспечения', + features: ['SECURE-T', 'Соловей', 'Веб-приложения'], + icon: , + color: 'from-blue-500 to-indigo-600' + }, + { + title: 'Оборудование', + description: 'Поставка компьютерной техники и электроники', + features: ['Серверы', 'Компьютеры', 'Сетевое оборудование'], + icon: , + color: 'from-cyan-500 to-teal-600' + }, + { + title: 'Антивирусы', + description: 'Лицензии Dr.Web для организаций', + features: ['Enterprise Suite', 'Security Space', 'Mobile Security'], + icon: , + color: 'from-green-500 to-emerald-600' + }, + { + title: 'Консультации', + description: 'Техническая поддержка и сопровождение', + features: ['Внедрение', 'Обучение', 'Поддержка 24/7'], + icon: , + color: 'from-purple-500 to-pink-600' + } + ].map((service, index) => ( +
+
+ {service.icon} +
+ +

{service.title}

+

{service.description}

+ +
+ {service.features.map((feature, featureIndex) => ( +
+ + {feature} +
+ ))} +
+
+ ))} +
+ + {/* CTA для снабженцев */} +
+
+

+ Для снабженцев и закупщиков +

+

+ Получите полный пакет документов для участия в тендере, включая сертификаты, + лицензии и техническую документацию. Поможем с подготовкой заявки. +

+ +
+
+
+ +
+

Полный пакет документов

+

Сертификаты, лицензии, ТТХ

+
+ +
+
+ +
+

Консультации

+

Помощь в подготовке заявки

+
+ +
+
+ +
+

Быстрая реакция

+

Ответ в течение 2 часов

+
+
+ +
+ + +
+
+
+
+
+ {/* Interactive Services Section */}
@@ -623,19 +1048,25 @@ model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')`
-
📧
+
+ +

Email

info@gundyrev.ru

-
📱
+
+ +

Телефон

+7 (XXX) XXX-XX-XX

-
💬
+
+ +

Telegram

@gundyrev

diff --git a/src/app/secure-t/page.tsx b/src/app/secure-t/page.tsx index d841d50..350fb72 100644 --- a/src/app/secure-t/page.tsx +++ b/src/app/secure-t/page.tsx @@ -397,10 +397,37 @@ export default function SecureT() {

SECURE-T

-

+

Комплексные решения для информационной безопасности и защиты данных

+ {/* Краткое описание продукта */} +
+

Что такое SECURE-T?

+

+ SECURE-T — это российская система защиты информации, сертифицированная ФСТЭК России. + Обеспечивает комплексную защиту корпоративных данных от внешних и внутренних угроз. +

+
+
+ + Сертификат ФСТЭК РФ +
+
+ + Соответствие 44-ФЗ и 223-ФЗ +
+
+ + Реестр отечественного ПО +
+
+ + Техподдержка 24/7 +
+
+
+ {/* Живая статистика */}
diff --git a/src/components/ui/avatar.tsx b/src/components/ui/avatar.tsx new file mode 100644 index 0000000..71e428b --- /dev/null +++ b/src/components/ui/avatar.tsx @@ -0,0 +1,53 @@ +"use client" + +import * as React from "react" +import * as AvatarPrimitive from "@radix-ui/react-avatar" + +import { cn } from "@/lib/utils" + +function Avatar({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AvatarImage({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AvatarFallback({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Avatar, AvatarImage, AvatarFallback } diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx new file mode 100644 index 0000000..0205413 --- /dev/null +++ b/src/components/ui/badge.tsx @@ -0,0 +1,46 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const badgeVariants = cva( + "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90", + secondary: + "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90", + destructive: + "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +function Badge({ + className, + variant, + asChild = false, + ...props +}: React.ComponentProps<"span"> & + VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot : "span" + + return ( + + ) +} + +export { Badge, badgeVariants } diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx new file mode 100644 index 0000000..a2df8dc --- /dev/null +++ b/src/components/ui/button.tsx @@ -0,0 +1,59 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", + { + variants: { + variant: { + default: + "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90", + destructive: + "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50", + secondary: + "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80", + ghost: + "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-9 px-4 py-2 has-[>svg]:px-3", + sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5", + lg: "h-10 rounded-md px-6 has-[>svg]:px-4", + icon: "size-9", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +) + +function Button({ + className, + variant, + size, + asChild = false, + ...props +}: React.ComponentProps<"button"> & + VariantProps & { + asChild?: boolean + }) { + const Comp = asChild ? Slot : "button" + + return ( + + ) +} + +export { Button, buttonVariants } diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx new file mode 100644 index 0000000..d05bbc6 --- /dev/null +++ b/src/components/ui/card.tsx @@ -0,0 +1,92 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +function Card({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardTitle({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardDescription({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardAction({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardContent({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +export { + Card, + CardHeader, + CardFooter, + CardTitle, + CardAction, + CardDescription, + CardContent, +} diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx new file mode 100644 index 0000000..d9ccec9 --- /dev/null +++ b/src/components/ui/dialog.tsx @@ -0,0 +1,143 @@ +"use client" + +import * as React from "react" +import * as DialogPrimitive from "@radix-ui/react-dialog" +import { XIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Dialog({ + ...props +}: React.ComponentProps) { + return +} + +function DialogTrigger({ + ...props +}: React.ComponentProps) { + return +} + +function DialogPortal({ + ...props +}: React.ComponentProps) { + return +} + +function DialogClose({ + ...props +}: React.ComponentProps) { + return +} + +function DialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DialogContent({ + className, + children, + showCloseButton = true, + ...props +}: React.ComponentProps & { + showCloseButton?: boolean +}) { + return ( + + + + {children} + {showCloseButton && ( + + + Close + + )} + + + ) +} + +function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function DialogFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function DialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogOverlay, + DialogPortal, + DialogTitle, + DialogTrigger, +} diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx new file mode 100644 index 0000000..03295ca --- /dev/null +++ b/src/components/ui/input.tsx @@ -0,0 +1,21 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +function Input({ className, type, ...props }: React.ComponentProps<"input">) { + return ( + + ) +} + +export { Input } diff --git a/src/components/ui/label.tsx b/src/components/ui/label.tsx new file mode 100644 index 0000000..fb5fbc3 --- /dev/null +++ b/src/components/ui/label.tsx @@ -0,0 +1,24 @@ +"use client" + +import * as React from "react" +import * as LabelPrimitive from "@radix-ui/react-label" + +import { cn } from "@/lib/utils" + +function Label({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Label } diff --git a/src/components/ui/navigation-menu.tsx b/src/components/ui/navigation-menu.tsx new file mode 100644 index 0000000..1199945 --- /dev/null +++ b/src/components/ui/navigation-menu.tsx @@ -0,0 +1,168 @@ +import * as React from "react" +import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu" +import { cva } from "class-variance-authority" +import { ChevronDownIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function NavigationMenu({ + className, + children, + viewport = true, + ...props +}: React.ComponentProps & { + viewport?: boolean +}) { + return ( + + {children} + {viewport && } + + ) +} + +function NavigationMenuList({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function NavigationMenuItem({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +const navigationMenuTriggerStyle = cva( + "group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:hover:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent data-[state=open]:bg-accent/50 focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1" +) + +function NavigationMenuTrigger({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + {children}{" "} + + ) +} + +function NavigationMenuContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function NavigationMenuViewport({ + className, + ...props +}: React.ComponentProps) { + return ( +
+ +
+ ) +} + +function NavigationMenuLink({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function NavigationMenuIndicator({ + className, + ...props +}: React.ComponentProps) { + return ( + +
+ + ) +} + +export { + NavigationMenu, + NavigationMenuList, + NavigationMenuItem, + NavigationMenuContent, + NavigationMenuTrigger, + NavigationMenuLink, + NavigationMenuIndicator, + NavigationMenuViewport, + navigationMenuTriggerStyle, +} diff --git a/src/components/ui/progress.tsx b/src/components/ui/progress.tsx new file mode 100644 index 0000000..e7a416c --- /dev/null +++ b/src/components/ui/progress.tsx @@ -0,0 +1,31 @@ +"use client" + +import * as React from "react" +import * as ProgressPrimitive from "@radix-ui/react-progress" + +import { cn } from "@/lib/utils" + +function Progress({ + className, + value, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +export { Progress } diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx new file mode 100644 index 0000000..dcbbc0c --- /dev/null +++ b/src/components/ui/select.tsx @@ -0,0 +1,185 @@ +"use client" + +import * as React from "react" +import * as SelectPrimitive from "@radix-ui/react-select" +import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Select({ + ...props +}: React.ComponentProps) { + return +} + +function SelectGroup({ + ...props +}: React.ComponentProps) { + return +} + +function SelectValue({ + ...props +}: React.ComponentProps) { + return +} + +function SelectTrigger({ + className, + size = "default", + children, + ...props +}: React.ComponentProps & { + size?: "sm" | "default" +}) { + return ( + + {children} + + + + + ) +} + +function SelectContent({ + className, + children, + position = "popper", + ...props +}: React.ComponentProps) { + return ( + + + + + {children} + + + + + ) +} + +function SelectLabel({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SelectItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ) +} + +function SelectSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SelectScrollUpButton({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +function SelectScrollDownButton({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +export { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectScrollDownButton, + SelectScrollUpButton, + SelectSeparator, + SelectTrigger, + SelectValue, +} diff --git a/src/components/ui/separator.tsx b/src/components/ui/separator.tsx new file mode 100644 index 0000000..275381c --- /dev/null +++ b/src/components/ui/separator.tsx @@ -0,0 +1,28 @@ +"use client" + +import * as React from "react" +import * as SeparatorPrimitive from "@radix-ui/react-separator" + +import { cn } from "@/lib/utils" + +function Separator({ + className, + orientation = "horizontal", + decorative = true, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Separator } diff --git a/src/components/ui/sheet.tsx b/src/components/ui/sheet.tsx new file mode 100644 index 0000000..84649ad --- /dev/null +++ b/src/components/ui/sheet.tsx @@ -0,0 +1,139 @@ +"use client" + +import * as React from "react" +import * as SheetPrimitive from "@radix-ui/react-dialog" +import { XIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Sheet({ ...props }: React.ComponentProps) { + return +} + +function SheetTrigger({ + ...props +}: React.ComponentProps) { + return +} + +function SheetClose({ + ...props +}: React.ComponentProps) { + return +} + +function SheetPortal({ + ...props +}: React.ComponentProps) { + return +} + +function SheetOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SheetContent({ + className, + children, + side = "right", + ...props +}: React.ComponentProps & { + side?: "top" | "right" | "bottom" | "left" +}) { + return ( + + + + {children} + + + Close + + + + ) +} + +function SheetHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function SheetFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function SheetTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SheetDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + Sheet, + SheetTrigger, + SheetClose, + SheetContent, + SheetHeader, + SheetFooter, + SheetTitle, + SheetDescription, +} diff --git a/src/components/ui/skeleton.tsx b/src/components/ui/skeleton.tsx new file mode 100644 index 0000000..32ea0ef --- /dev/null +++ b/src/components/ui/skeleton.tsx @@ -0,0 +1,13 @@ +import { cn } from "@/lib/utils" + +function Skeleton({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +export { Skeleton } diff --git a/src/components/ui/textarea.tsx b/src/components/ui/textarea.tsx new file mode 100644 index 0000000..7f21b5e --- /dev/null +++ b/src/components/ui/textarea.tsx @@ -0,0 +1,18 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +function Textarea({ className, ...props }: React.ComponentProps<"textarea">) { + return ( +