feat: Добавить анимации и улучшения UX/UI в компоненты приложения, включая плавные переходы, эффекты при наведении и анимации для модальных окон. Обновить карточки и таблицы с новыми анимациями для улучшения визуального восприятия и доступности.
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 2m42s

This commit is contained in:
2025-10-02 19:17:25 +07:00
parent cd5e169bc6
commit 8952c4a897
12 changed files with 1267 additions and 143 deletions
+136 -14
View File
@@ -1,6 +1,9 @@
import { useState, useEffect, useRef } from 'react';
import api from './lib/api.js';
import ConfirmDialog from './components/ConfirmDialog.jsx';
import FormModal from './components/FormModal.jsx';
import ConfirmModal from './components/ConfirmModal.jsx';
import FormField from './components/FormField.jsx';
import {
IconPlus,
IconSearch,
@@ -18,7 +21,8 @@ import {
IconChevronDown,
IconLink,
IconFilter,
IconMapPin
IconMapPin,
IconWorld
} from '@tabler/icons-react';
import GraphView from './GraphView';
@@ -691,12 +695,23 @@ function ServerManager() {
)}
</div>
{/* Delete Modal */}
<DeleteServerModal
{/* Delete Modal - New unified component */}
<ConfirmModal
show={showDeleteModal}
server={serverToDelete}
onDelete={executeDelete}
onClose={() => setShowDeleteModal(false)}
onConfirm={executeDelete}
title="Подтверждение удаления"
message={
serverToDelete ? (
<>
<p>Вы уверены, что хотите удалить сервер <strong>{serverToDelete.ip}</strong>?</p>
<p className="text-muted mb-0">Это действие нельзя отменить.</p>
</>
) : null
}
confirmLabel="Удалить"
variant="danger"
icon={IconTrash}
/>
{/* Edit Server Modal */}
@@ -719,17 +734,124 @@ function ServerManager() {
onClose={handleLinkGeneratorClose}
/>
{/* Add Server Modal */}
<AddServerModal
{/* Add Server Modal - New unified component */}
<FormModal
show={addServerModalOpen}
newServer={newServer}
customProvider={customProvider}
onNewServerChange={setNewServer}
onCustomProviderChange={setCustomProvider}
onAddServer={handleAddServerFromModal}
onClose={handleCloseAddServerModal}
error={error}
/>
onSubmit={handleAddServerFromModal}
title="Добавить новый сервер"
submitLabel="Добавить сервер"
submitIcon={IconPlus}
size="md"
>
{error && (
<div className="alert alert-danger mb-3" role="alert">
{error}
</div>
)}
<FormField
label="IP адрес"
name="ip"
value={newServer.ip}
onChange={(val) => setNewServer({ ...newServer, ip: val })}
placeholder="192.168.1.1"
required
icon={IconServer}
helpText="Введите IPv4 адрес сервера"
/>
<FormField
label="DNS имя"
name="dns"
value={newServer.dns}
onChange={(val) => setNewServer({ ...newServer, dns: val })}
placeholder="srv1.shx.su"
required
icon={IconWorld}
helpText="Полное доменное имя сервера"
/>
<FormField
label="Страна"
name="country"
type="select"
value={newServer.country}
onChange={(val) => setNewServer({ ...newServer, country: val })}
required
icon={IconMapPin}
options={[
{ value: '', label: 'Выберите страну', disabled: true },
{ value: 'RU', label: 'Россия (RU)' },
{ value: 'SWE', label: 'Швеция (SWE)' },
{ value: 'US', label: 'США (US)' },
{ value: 'DE', label: 'Германия (DE)' },
{ value: 'NL', label: 'Нидерланды (NL)' },
{ value: 'SG', label: 'Сингапур (SG)' }
]}
/>
<FormField
label="Провайдер"
name="provider"
type="select"
value={newServer.provider}
onChange={(val) => setNewServer({ ...newServer, provider: val })}
required
options={[
{ value: '', label: 'Выберите провайдера', disabled: true },
{ value: 'Yandex', label: 'Yandex Cloud' },
{ value: 'AWS', label: 'Amazon Web Services' },
{ value: 'Google', label: 'Google Cloud' },
{ value: 'Azure', label: 'Microsoft Azure' },
{ value: 'Hetzner', label: 'Hetzner' },
{ value: 'OVH', label: 'OVH' },
{ value: 'DigitalOcean', label: 'DigitalOcean' },
{ value: 'Vultr', label: 'Vultr' },
{ value: 'Linode', label: 'Linode' },
{ value: 'VPSVILLE', label: 'VPSVILLE' },
{ value: 'HIPHOST', label: 'HIPHOST' },
{ value: 'Другой', label: 'Другой' }
]}
/>
{newServer.provider === 'Другой' && (
<FormField
label="Название провайдера"
name="customProvider"
value={customProvider}
onChange={setCustomProvider}
placeholder="Введите название провайдера"
required
helpText="Укажите название вашего провайдера"
/>
)}
<FormField
label="Тип туннеля"
name="tunnel"
type="select"
value={newServer.tunnel}
onChange={(val) => setNewServer({ ...newServer, tunnel: val })}
required
options={[
{ value: 'GRE', label: 'GRE (Generic Routing Encapsulation)' },
{ value: 'IPSec', label: 'IPSec' },
{ value: 'WireGuard', label: 'WireGuard' },
{ value: 'OpenVPN', label: 'OpenVPN' }
]}
/>
<FormField
label="Основной шлюз"
name="gateway"
value={newServer.gateway}
onChange={(val) => setNewServer({ ...newServer, gateway: val })}
placeholder="Cloudflare, Hetzner, Мой шлюз и т.д."
required
helpText="Имя основного шлюза для маршрутизации"
/>
</FormModal>
<div className="card w-100 mb-4">
<div className="card-header d-flex justify-content-between align-items-center">