Files
futriix/internal/api/static/style.css

1186 lines
22 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright 2026 Safronov Grigorii
*
* Licensed under the CDDL, Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
*
* You may obtain a copy of the License at
* https://opensource.org/licenses/CDDL-1.0
*/
/* Файл: internal/api/static/style.css */
/* Стили для веб-интерфейса Futriis DB Dashboard */
:root {
--primary-color: #00bfff;
--primary-dark: #0099cc;
--secondary-color: #6c757d;
--success-color: #28a745;
--danger-color: #dc3545;
--warning-color: #ffc107;
--info-color: #17a2b8;
--bg-dark: #1a1a2e;
--bg-sidebar: #005385;
--bg-card: #0f3460;
--bg-hover: #1a1f3a;
--text-primary: #ffffff;
--text-secondary: #b8c6db;
--border-color: #2d3a5e;
--shadow-sm: 0 2px 4px rgba(0,0,0,0.1);
--shadow-md: 0 4px 8px rgba(0,0,0,0.15);
--shadow-lg: 0 8px 16px rgba(0,0,0,0.2);
--transition: all 0.3s ease;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: var(--bg-dark);
color: var(--text-primary);
overflow: hidden;
}
/* Dashboard Container */
.dashboard-container {
display: flex;
height: 100vh;
width: 100%;
}
/* Sidebar - Вертикальное меню */
.sidebar {
width: 280px;
background: var(--bg-sidebar);
display: flex;
flex-direction: column;
transition: var(--transition);
box-shadow: var(--shadow-lg);
z-index: 100;
overflow-y: auto;
overflow-x: hidden;
}
.sidebar-header {
padding: 24px 20px;
border-bottom: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: space-between;
}
.logo {
display: flex;
align-items: center;
gap: 12px;
font-size: 1.5rem;
font-weight: 700;
}
.logo img {
width: 225px;
height: 107px;
object-fit: contain;
}
.logo span {
background: linear-gradient(135deg, var(--primary-color), #00ffcc);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.menu-toggle {
display: none;
background: none;
border: none;
color: var(--text-primary);
font-size: 1.2rem;
cursor: pointer;
padding: 8px;
}
/* Navigation Menu */
.nav-menu {
flex: 1;
list-style: none;
padding: 20px 0;
}
.nav-item {
margin-bottom: 4px;
}
.nav-link {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 20px;
color: var(--text-secondary);
text-decoration: none;
transition: var(--transition);
border-radius: 8px;
margin: 0 8px;
}
.nav-link:hover {
background: var(--bg-hover);
color: var(--text-primary);
}
.nav-link.active {
background: var(--primary-color);
color: white;
}
.nav-link i {
width: 24px;
font-size: 1.1rem;
}
.nav-link span {
flex: 1;
}
/* Submenu */
.has-submenu > .nav-link {
position: relative;
}
.has-submenu > .nav-link .fa-chevron-down {
margin-left: auto;
transition: var(--transition);
}
.has-submenu.open > .nav-link .fa-chevron-down {
transform: rotate(180deg);
}
.submenu {
list-style: none;
padding-left: 56px;
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
}
.has-submenu.open .submenu {
max-height: 500px;
}
.submenu li a {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 16px;
color: var(--text-secondary);
text-decoration: none;
font-size: 0.9rem;
transition: var(--transition);
border-radius: 6px;
margin: 2px 8px;
}
.submenu li a:hover {
background: var(--bg-hover);
color: var(--text-primary);
}
.submenu li a i {
width: 20px;
font-size: 0.9rem;
}
/* Sidebar Footer */
.sidebar-footer {
padding: 20px;
border-top: 1px solid var(--border-color);
}
.user-info {
display: flex;
align-items: center;
gap: 12px;
padding: 12px;
background: var(--bg-dark);
border-radius: 8px;
margin-bottom: 12px;
}
.user-info i {
font-size: 1.2rem;
color: var(--primary-color);
}
.logout-btn {
width: 100%;
display: flex;
align-items: center;
gap: 12px;
padding: 10px 16px;
background: var(--danger-color);
border: none;
color: white;
border-radius: 8px;
cursor: pointer;
font-size: 1rem;
transition: var(--transition);
}
.logout-btn:hover {
background: #c82333;
transform: translateY(-1px);
}
/* Main Content */
.main-content {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
.top-bar {
background: #1a1a2e;
padding: 16px 24px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid var(--border-color);
}
.top-bar h1 {
font-size: 1.5rem;
font-weight: 600;
}
.connection-status {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
background: var(--bg-dark);
border-radius: 24px;
font-size: 0.9rem;
font-weight: 500;
}
.connection-status i {
font-size: 0.8rem;
display: none;
}
.connection-status.online {
color: #00ff88;
background: rgba(0, 255, 136, 0.15);
text-shadow: 0 0 8px rgba(0, 255, 136, 0.5);
}
.connection-status.offline {
color: var(--danger-color);
background: rgba(220, 53, 69, 0.1);
}
.connection-status.online i {
display: none;
}
.connection-status.offline i {
display: none;
}
.connection-status::before {
content: "●";
margin-right: 8px;
font-size: 12px;
animation: pulse 2s infinite;
}
@keyframes pulse {
0% {
opacity: 0.6;
text-shadow: 0 0 2px currentColor;
}
50% {
opacity: 1;
text-shadow: 0 0 10px currentColor;
}
100% {
opacity: 0.6;
text-shadow: 0 0 2px currentColor;
}
}
.connection-status.online::before {
color: #00ff88;
}
.connection-status.offline::before {
color: var(--danger-color);
animation: none;
}
.content-area {
flex: 1;
overflow-y: auto;
padding: 24px;
}
/* Dashboard Cards */
.dashboard-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.stat-card {
background: var(--bg-card);
border-radius: 12px;
padding: 20px;
display: flex;
align-items: center;
gap: 16px;
transition: var(--transition);
}
.stat-card:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}
.stat-icon {
width: 60px;
height: 60px;
background: rgba(0, 191, 255, 0.1);
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
}
.stat-icon i {
font-size: 2rem;
color: var(--primary-color);
}
.stat-info h3 {
font-size: 1.8rem;
font-weight: 700;
}
.stat-info p {
color: var(--text-secondary);
font-size: 0.85rem;
}
/* Tables */
.data-table {
width: 100%;
background: var(--bg-card);
border-radius: 12px;
overflow-x: auto;
}
.data-table table {
width: 100%;
border-collapse: collapse;
}
.data-table th,
.data-table td {
padding: 12px 16px;
text-align: left;
border-bottom: 1px solid var(--border-color);
}
.data-table th {
background: var(--bg-sidebar);
font-weight: 600;
color: var(--primary-color);
}
.data-table tr:hover {
background: var(--bg-hover);
}
/* Forms */
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 500;
}
.form-control {
width: 100%;
padding: 10px 12px;
background: #1a1a2e;
border: 1px solid var(--border-color);
border-radius: 8px;
color: var(--text-primary);
font-size: 0.95rem;
transition: var(--transition);
}
.form-control:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 2px rgba(0, 191, 255, 0.2);
background: #1a1a2e;
}
/* Подсветка полей ввода при наведении мыши - только рамка */
.form-control:hover {
border-color: var(--primary-color);
background: #1a1a2e;
}
textarea.form-control {
min-height: 120px;
font-family: monospace;
resize: vertical;
}
/* Buttons - общие стили для всех кнопок */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 10px 20px;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 0.95rem;
font-weight: 500;
transition: var(--transition);
text-decoration: none;
width: auto;
min-width: 80px;
}
/* Стили для кнопки "Войти" (primary) */
.btn-primary {
background: #1a1a2e;
color: white;
}
.btn-primary:hover {
background: #2a2a4e;
transform: translateY(-1px);
}
/* Стили для кнопки "Отмена" (secondary) - полностью идентичны кнопке "Войти" */
.btn-secondary {
background: #1a1a2e;
color: white;
}
.btn-secondary:hover {
background: #2a2a4e;
transform: translateY(-1px);
}
.btn-danger {
background: var(--danger-color);
color: white;
}
.btn-danger:hover {
background: #c82333;
}
.btn-sm {
padding: 6px 12px;
font-size: 0.85rem;
}
/* Modal */
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
z-index: 1000;
align-items: center;
justify-content: center;
}
.modal.show {
display: flex;
}
.modal-content {
background: #005385;
border-radius: 16px;
width: 90%;
max-width: 500px;
max-height: 80vh;
display: flex;
flex-direction: column;
animation: modalSlideIn 0.3s ease;
position: relative;
}
@keyframes modalSlideIn {
from {
transform: translateY(-50px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
.modal-header {
padding: 20px 24px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
display: flex;
justify-content: space-between;
align-items: center;
}
.modal-header h2 {
font-size: 1.5rem;
font-weight: 600;
color: var(--text-primary);
margin: 0;
}
.modal-close {
background: none;
border: none;
font-size: 1.5rem;
cursor: pointer;
color: var(--text-secondary);
padding: 0;
/* width: 32px; */
/* height: 32px; */
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
transition: var(--transition);
}
.modal-close:hover {
background: rgba(255, 255, 255, 0.1);
color: var(--text-primary);
}
.modal-body {
padding: 24px;
overflow-y: auto;
flex: 1;
}
.modal-footer {
padding: 16px 24px;
border-top: 1px solid rgba(255, 255, 255, 0.1);
display: flex;
justify-content: flex-end;
gap: 12px;
flex-direction: row-reverse;
}
/* Стили для кнопок в модальном окне - обе кнопки имеют одинаковый фон на всю площадь */
.modal-footer .btn {
font-size: 0.9rem;
padding: 10px 24px;
border-radius: 8px;
width: auto;
min-width: 100px;
}
/* Кнопка "Войти" в модальном окне */
.modal-footer .btn-primary {
background: #1a1a2e;
color: white;
border: none;
}
.modal-footer .btn-primary:hover {
background: #2a2a4e;
transform: translateY(-1px);
}
/* Кнопка "Отмена" в модальном окне - полностью идентична кнопке "Войти" */
.modal-footer .btn-secondary {
background: #1a1a2e;
color: white;
border: none;
}
.modal-footer .btn-secondary:hover {
background: #2a2a4e;
transform: translateY(-1px);
}
/* Notifications */
.notification-container {
position: fixed;
top: 20px;
right: 20px;
z-index: 1100;
}
.notification {
background: var(--bg-card);
border-radius: 8px;
padding: 12px 20px;
margin-bottom: 10px;
display: flex;
align-items: center;
gap: 12px;
box-shadow: var(--shadow-lg);
animation: slideInRight 0.3s ease;
}
@keyframes slideInRight {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
.notification.success {
border-left: 4px solid var(--success-color);
}
.notification.error {
border-left: 4px solid var(--danger-color);
}
.notification.warning {
border-left: 4px solid var(--warning-color);
}
.notification.info {
border-left: 4px solid var(--info-color);
}
/* Loading Spinner */
.loading-spinner {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 200px;
}
.loading-spinner i {
font-size: 3rem;
color: var(--primary-color);
}
.loading-spinner p {
margin-top: 16px;
color: var(--text-secondary);
}
/* Tabs */
.tabs {
display: flex;
gap: 8px;
margin-bottom: 20px;
border-bottom: 1px solid var(--border-color);
padding-bottom: 8px;
}
.tab-btn {
padding: 8px 16px;
background: none;
border: none;
color: var(--text-secondary);
cursor: pointer;
border-radius: 6px;
transition: var(--transition);
}
.tab-btn.active {
background: var(--primary-color);
color: white;
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
/* Responsive Design */
@media (max-width: 768px) {
.sidebar {
position: fixed;
left: -280px;
height: 100%;
transition: left 0.3s ease;
}
.sidebar.open {
left: 0;
}
.menu-toggle {
display: block;
}
.main-content {
margin-left: 0;
}
.dashboard-stats {
grid-template-columns: 1fr;
}
.data-table {
font-size: 0.85rem;
}
.data-table th,
.data-table td {
padding: 8px 12px;
}
.modal-content {
width: 95%;
margin: 20px;
}
.logo img {
width: 180px;
height: 86px;
}
}
@media (max-width: 480px) {
.top-bar h1 {
font-size: 1.2rem;
}
.stat-card {
padding: 16px;
}
.stat-icon {
width: 50px;
height: 50px;
}
.stat-info h3 {
font-size: 1.4rem;
}
.logo img {
width: 150px;
height: 71px;
}
.connection-status {
padding: 4px 10px;
font-size: 0.75rem;
}
.connection-status::before {
font-size: 8px;
margin-right: 4px;
}
}
/* Scrollbar Styling */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: var(--bg-dark);
}
::-webkit-scrollbar-thumb {
background: var(--border-color);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--primary-color);
}
/* ==================== Дополнительные стили для новых компонентов ==================== */
/* Badges and status indicators */
.badge {
display: inline-block;
padding: 4px 8px;
background: var(--primary-color);
color: white;
border-radius: 4px;
font-size: 0.75rem;
margin: 2px;
}
.status-badge {
display: inline-block;
padding: 4px 12px;
border-radius: 20px;
font-size: 0.75rem;
font-weight: 500;
}
.status-badge.status-active {
background: rgba(40, 167, 69, 0.2);
color: #28a745;
border: 1px solid rgba(40, 167, 69, 0.3);
}
.status-badge.status-inactive {
background: rgba(220, 53, 69, 0.2);
color: #dc3545;
border: 1px solid rgba(220, 53, 69, 0.3);
}
/* Success and error messages */
.success-message {
background: rgba(40, 167, 69, 0.1);
border: 1px solid rgba(40, 167, 69, 0.3);
border-radius: 8px;
padding: 16px;
text-align: center;
}
.success-message i {
font-size: 2rem;
color: #28a745;
margin-bottom: 8px;
}
.error-message {
background: rgba(220, 53, 69, 0.1);
border: 1px solid rgba(220, 53, 69, 0.3);
border-radius: 8px;
padding: 16px;
text-align: center;
color: #dc3545;
}
/* Code styling */
code {
font-family: 'Courier New', monospace;
background: var(--bg-dark);
padding: 2px 6px;
border-radius: 4px;
font-size: 0.85rem;
}
/* Select dropdown styling */
select.form-control {
cursor: pointer;
appearance: none;
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'%3e%3cpath d='M7 10l5 5 5-5z'/%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: right 12px center;
background-size: 16px;
}
/* Better table styling */
.data-table table {
font-size: 0.85rem;
}
.data-table td code {
word-break: break-all;
max-width: 300px;
display: inline-block;
}
/* Button variants */
.btn-warning {
background: #ffc107;
color: #1a1a2e;
}
.btn-warning:hover {
background: #e0a800;
transform: translateY(-1px);
}
.btn-success {
background: #28a745;
color: white;
}
.btn-success:hover {
background: #218838;
transform: translateY(-1px);
}
/* Animation for notifications */
@keyframes slideOutRight {
from {
transform: translateX(0);
opacity: 1;
}
to {
transform: translateX(100%);
opacity: 0;
}
}
/* Responsive adjustments for new components */
@media (max-width: 768px) {
.data-table td code {
max-width: 150px;
font-size: 0.7rem;
}
.badge {
font-size: 0.65rem;
padding: 2px 6px;
}
.btn-sm {
padding: 4px 8px;
font-size: 0.75rem;
}
}
/* Submenu open state */
.has-submenu.open .submenu {
max-height: 500px;
}
/* Transaction status indicators */
.transaction-status {
display: inline-block;
width: 10px;
height: 10px;
border-radius: 50%;
margin-right: 8px;
}
.transaction-status.active {
background: #28a745;
box-shadow: 0 0 5px #28a745;
}
.transaction-status.pending {
background: #ffc107;
box-shadow: 0 0 5px #ffc107;
}
/* File input styling */
input[type="file"].form-control {
padding: 8px;
cursor: pointer;
}
input[type="file"].form-control::file-selector-button {
background: var(--primary-color);
color: white;
border: none;
padding: 6px 12px;
border-radius: 4px;
cursor: pointer;
margin-right: 12px;
}
input[type="file"].form-control::file-selector-button:hover {
background: var(--primary-dark);
}
/* ==================== Стили для триггеров ==================== */
/* Trigger status badges */
.status-badge.status-enabled {
background: rgba(40, 167, 69, 0.2);
color: #28a745;
border: 1px solid rgba(40, 167, 69, 0.3);
}
.status-badge.status-disabled {
background: rgba(108, 117, 125, 0.2);
color: #6c757d;
border: 1px solid rgba(108, 117, 125, 0.3);
}
/* Trigger event badges */
.event-badge {
display: inline-block;
padding: 2px 8px;
border-radius: 4px;
font-size: 0.7rem;
font-weight: 500;
}
.event-before {
background: rgba(255, 193, 7, 0.2);
color: #ffc107;
}
.event-after {
background: rgba(23, 162, 184, 0.2);
color: #17a2b8;
}
/* Trigger actions styling */
.trigger-action {
font-family: monospace;
font-size: 0.8rem;
}
/* ==================== Стили для ограничений (Constraints) ==================== */
/* Constraint sections */
.constraint-section {
background: var(--bg-card);
border-radius: 12px;
padding: 20px;
margin-bottom: 24px;
}
.constraint-section h4 {
margin-bottom: 16px;
display: flex;
align-items: center;
gap: 8px;
color: var(--primary-color);
}
.constraint-section h4 i {
font-size: 1.1rem;
}
.constraint-section .data-table {
background: transparent;
}
.constraint-section .data-table th {
background: rgba(0, 0, 0, 0.2);
}
/* Constraint badges */
.constraint-badge {
display: inline-block;
padding: 2px 8px;
border-radius: 4px;
font-size: 0.7rem;
font-weight: 500;
margin-right: 6px;
}
.constraint-badge-required {
background: rgba(255, 193, 7, 0.2);
color: #ffc107;
}
.constraint-badge-unique {
background: rgba(40, 167, 69, 0.2);
color: #28a745;
}
.constraint-badge-min {
background: rgba(23, 162, 184, 0.2);
color: #17a2b8;
}
.constraint-badge-max {
background: rgba(23, 162, 184, 0.2);
color: #17a2b8;
}
.constraint-badge-enum {
background: rgba(111, 66, 193, 0.2);
color: #6f42c1;
}
.constraint-badge-regex {
background: rgba(220, 53, 69, 0.2);
color: #dc3545;
}
/* Constraint value display */
.constraint-value {
font-family: monospace;
background: var(--bg-dark);
padding: 2px 6px;
border-radius: 4px;
font-size: 0.8rem;
}
.enum-values {
display: flex;
flex-wrap: wrap;
gap: 4px;
}
.enum-values .badge {
background: var(--primary-color);
color: white;
font-size: 0.7rem;
padding: 2px 8px;
}
/* Constraint form styles */
.constraint-form-row {
display: flex;
gap: 12px;
align-items: flex-end;
margin-bottom: 16px;
}
.constraint-form-row .form-group {
flex: 1;
margin-bottom: 0;
}
.constraint-help-text {
font-size: 0.75rem;
color: var(--text-secondary);
margin-top: 4px;
}
/* Responsive for constraints */
@media (max-width: 768px) {
.constraint-section {
padding: 12px;
}
.constraint-section h4 {
font-size: 1rem;
}
.constraint-form-row {
flex-direction: column;
gap: 12px;
}
.constraint-form-row .form-group {
width: 100%;
}
.enum-values .badge {
font-size: 0.65rem;
}
}