Files
magistr/frontend/admin/settings/css/main.css
dipatrik10 97bf3cc50a feat: завершить миграцию фронтенда на React (этапы 1-5)
Админка, настройки, логин, кабинеты преподавателя и студента
полностью переведены на React 19 (модель strangler, docs/REACT_MIGRATION.md).

- 15 вкладок админки: lazy-загрузка, общий error boundary, сервисный слой
- Удалены legacy-views и переходный слой LegacyTabView (45 файлов)
- Сборка esbuild (frontend/scripts/build-react.mjs) с бюджетами gzip на чанки
- CSP-хэши, кэширование: chunk'и immutable, CSS/HTML no-cache (react-cache.conf)
- Фиксы: lazy-импорт именованных экспортов (краш после авторизации),
  растяжение #admin-root/#settings-root на всю ширину,
  возврат subjects/lessonTypes из справочников (краш просмотра расписаний),
  отказ от заведомо широкого поиска расписания без выбранной цели,
  центрирование карточки логина
- Тесты: 237/237 (npm run check), регрессионные на lazy-вкладки и ширину
- Документация: REACT_MIGRATION.md, REACT_MIGRATION_RESULT.md, FRONTEND.md
2026-09-28 23:15:04 +03:00

634 lines
14 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.
/* ===== Сброс и база ===== */
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--bg-primary: #0a0a0f;
--bg-sidebar: rgba(255, 255, 255, 0.02);
--bg-card: rgba(255, 255, 255, 0.03);
--bg-card-border: rgba(255, 255, 255, 0.05);
--bg-input: rgba(255, 255, 255, 0.04);
--bg-input-focus: rgba(255, 255, 255, 0.08);
--bg-hover: rgba(255, 255, 255, 0.06);
--text-primary: #f8fafc;
--text-secondary: #94a3b8;
--text-placeholder: #475569;
--accent: #8b5cf6;
--accent-hover: #a78bfa;
--accent-glow: rgba(139, 92, 246, 0.4);
--accent-secondary: #ec4899;
--error: #ef4444;
--success: #10b981;
--warning: #f59e0b;
--radius-sm: 10px;
--radius-md: 16px;
--transition: 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
}
/* ===== Светлая тема ===== */
[data-theme="light"] {
--bg-primary: #f8fafc;
--bg-sidebar: rgba(255, 255, 255, 0.7);
--bg-card: rgba(255, 255, 255, 0.75);
--bg-card-border: rgba(0, 0, 0, 0.08);
--bg-input: rgba(0, 0, 0, 0.03);
--bg-input-focus: rgba(0, 0, 0, 0.06);
--bg-hover: rgba(0, 0, 0, 0.05);
--text-primary: #0f172a;
--text-secondary: #475569;
--text-placeholder: #94a3b8;
--accent: #4F46E5;
--accent-hover: #4338CA;
--accent-glow: rgba(79, 70, 229, 0.3);
--accent-secondary: #d946ef;
--error: #ef4444;
--success: #10b981;
--warning: #f59e0b;
}
html {
font-size: 16px;
-webkit-font-smoothing: antialiased;
}
body {
font-family: var(--ui-font-sans, 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif);
background: var(--bg-primary);
color: var(--text-primary);
min-height: 100vh;
display: flex;
transition: background 0.4s ease, color 0.4s ease;
}
/* ===== Анимации ===== */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(4px); }
to { opacity: 1; transform: translateY(0); }
}
/* ===== Переключатель темы ===== */
.theme-toggle {
width: 40px;
height: 40px;
border-radius: var(--button-radius);
background: var(--button-secondary-bg);
border: 1px solid var(--button-secondary-border);
color: var(--button-secondary-text);
display: inline-flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
padding: 0;
transition: background var(--transition), border-color var(--transition), color var(--transition), box-shadow var(--transition), transform var(--transition);
z-index: 100;
flex-shrink: 0;
}
.theme-toggle svg {
width: 20px;
height: 20px;
transition: transform 0.4s ease;
}
.theme-toggle:hover {
background: var(--button-secondary-bg-hover);
border-color: var(--button-secondary-border);
transform: translateY(-1px);
}
.theme-toggle:active {
transform: translateY(0);
}
.theme-toggle:focus-visible {
outline: none;
box-shadow: 0 0 0 3px var(--button-focus-ring);
}
.theme-toggle--fixed {
position: fixed;
top: 1.25rem;
right: 1.25rem;
}
/* ===== Заглушка настроек ===== */
.settings-placeholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
padding: 4rem 2rem;
animation: fadeIn 0.4s ease both;
}
.settings-placeholder .icon-wrap {
width: 80px;
height: 80px;
border-radius: 50%;
background: linear-gradient(135deg, rgba(139, 92, 246, 0.15), rgba(236, 72, 153, 0.15));
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 1.5rem;
box-shadow: 0 0 30px var(--accent-glow);
}
.settings-placeholder h2 {
font-size: 1.5rem;
font-weight: 700;
margin-bottom: 0.5rem;
}
.settings-placeholder p {
color: var(--text-secondary);
font-size: 0.95rem;
max-width: 400px;
line-height: 1.6;
}
/* ===== Рабочие области настроек ===== */
.settings-section {
display: flex;
flex-direction: column;
gap: 1.25rem;
animation: fadeIn 0.25s ease both;
}
.settings-header-row,
.card-header-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
}
.settings-header-row h2,
.settings-card h3 {
margin: 0;
color: var(--text-primary);
}
.settings-header-row h2 {
font-size: 1.35rem;
font-weight: 700;
}
.settings-header-row p {
margin-top: 0.25rem;
color: var(--text-secondary);
line-height: 1.5;
}
.settings-grid {
display: grid;
grid-template-columns: minmax(0, 2fr) minmax(260px, 1fr);
gap: 1.25rem;
align-items: start;
}
.settings-grid-tables {
grid-template-columns: minmax(0, 1.6fr) minmax(320px, 0.9fr);
}
.settings-card {
border: 1px solid var(--bg-card-border);
border-radius: var(--radius-sm);
background: var(--bg-card);
padding: 1rem;
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
}
.settings-card-compact {
display: flex;
flex-direction: column;
gap: 0.9rem;
}
.settings-form {
display: grid;
grid-template-columns: minmax(160px, 1.3fr) minmax(100px, 0.7fr) repeat(3, minmax(120px, 1fr));
gap: 0.85rem;
margin-top: 1rem;
align-items: end;
}
.settings-form-compact {
grid-template-columns: minmax(220px, 1.2fr) minmax(180px, 1fr) auto;
}
.settings-form-single {
grid-template-columns: minmax(240px, 1fr);
}
.settings-form-assignment {
grid-template-columns: minmax(150px, 0.8fr) minmax(190px, 1fr) auto;
}
.form-field {
display: flex;
flex-direction: column;
gap: 0.4rem;
color: var(--text-secondary);
font-size: 0.82rem;
font-weight: 600;
}
.form-field input,
.form-field select {
width: 100%;
min-height: 42px;
border: 1px solid var(--bg-card-border);
border-radius: var(--radius-sm);
background: var(--bg-input);
color: var(--text-primary);
padding: 0 0.75rem;
font: inherit;
outline: none;
transition: border-color var(--transition), background var(--transition), box-shadow var(--transition);
}
.form-field input:focus,
.form-field select:focus {
border-color: var(--accent);
background: var(--bg-input-focus);
box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.16);
}
.native-select-control {
cursor: pointer;
}
.form-alert {
grid-column: 1 / -1;
min-height: 0;
border-radius: var(--radius-sm);
font-size: 0.9rem;
}
.form-alert.success,
.form-alert.error {
padding: 0.75rem 0.9rem;
}
.form-alert.success {
color: var(--success);
background: rgba(16, 185, 129, 0.12);
border: 1px solid rgba(16, 185, 129, 0.24);
}
.form-alert.error {
color: var(--error);
background: rgba(239, 68, 68, 0.12);
border: 1px solid rgba(239, 68, 68, 0.24);
}
.scope-summary {
display: flex;
align-items: center;
gap: 0.7rem;
margin-top: 1rem;
border: 1px solid var(--bg-card-border);
border-radius: var(--radius-sm);
padding: 0.75rem;
background: rgba(255, 255, 255, 0.02);
color: var(--text-secondary);
font-size: 0.9rem;
line-height: 1.45;
}
.scope-header-actions {
display: flex;
flex-wrap: wrap;
justify-content: flex-end;
gap: 0.6rem;
}
.table-wrap {
overflow-x: auto;
}
.settings-table {
width: 100%;
border-collapse: collapse;
min-width: 680px;
}
.settings-table-compact {
min-width: 420px;
}
.settings-table th,
.settings-table td {
border-bottom: 1px solid var(--bg-card-border);
padding: 0.7rem 0.75rem;
text-align: left;
vertical-align: middle;
}
.settings-table th {
color: var(--text-secondary);
font-size: 0.78rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0;
}
.settings-table td {
color: var(--text-primary);
font-size: 0.92rem;
}
.settings-table tr:last-child td {
border-bottom: none;
}
.loading-row {
text-align: center;
color: var(--text-secondary);
padding: 1.25rem !important;
}
/* Карточка статуса текущего подключения к БД (замена inline-стилей legacy) */
.db-status-card {
display: flex;
align-items: flex-start;
}
.db-status-grid {
display: flex;
align-items: center;
gap: 1rem;
flex-wrap: wrap;
width: 100%;
}
.db-status-grid > div {
display: flex;
align-items: center;
gap: 0.4rem;
flex-wrap: wrap;
}
.db-status-grid span {
color: var(--text-secondary);
font-size: 0.85rem;
}
.db-status-grid code {
font-size: 0.85rem;
}
/* Широкое поле формы и выравнивание кнопок действий в строке формы */
.form-group-wide {
flex: 3;
}
.form-row-actions {
height: fit-content;
}
.scope-badge {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 42px;
min-height: 28px;
border-radius: 999px;
background: rgba(236, 72, 153, 0.14);
color: #f9a8d4;
border: 1px solid rgba(236, 72, 153, 0.25);
font-weight: 800;
}
.scope-badge-base {
min-width: 86px;
background: rgba(139, 92, 246, 0.15);
color: var(--accent-hover);
border-color: rgba(139, 92, 246, 0.28);
}
.actions-cell {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.custom-select-wrapper {
position: relative;
width: 100%;
}
.select-layer-active {
position: relative !important;
z-index: 10001 !important;
}
.custom-select-wrapper.open {
z-index: 10002 !important;
}
.custom-select-trigger {
width: 100%;
min-height: 42px;
border: 1px solid var(--bg-card-border);
border-radius: var(--radius-sm);
background: var(--bg-input);
color: var(--text-primary);
padding: 0 0.75rem;
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.75rem;
cursor: pointer;
transition: border-color var(--transition), background var(--transition), box-shadow var(--transition);
}
.custom-select-trigger:hover,
.custom-select-trigger:focus,
.custom-select-wrapper.open .custom-select-trigger {
border-color: var(--accent);
background: var(--bg-input-focus);
box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.16);
}
.custom-select-text {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.custom-select-icon {
display: flex;
color: var(--text-secondary);
transition: transform var(--transition);
}
.custom-select-wrapper.open .custom-select-icon {
transform: rotate(180deg);
}
.custom-select-menu {
position: absolute;
top: calc(100% + 0.35rem);
left: 0;
right: 0;
max-height: 260px;
overflow-y: auto;
margin: 0;
padding: 0.35rem;
list-style: none;
border: 1px solid var(--bg-card-border);
border-radius: var(--radius-sm);
background: rgba(10, 10, 15, 0.96);
box-shadow: 0 18px 40px rgba(0, 0, 0, 0.24);
opacity: 0;
visibility: hidden;
transform: translateY(-4px);
transition: opacity var(--transition), transform var(--transition), visibility var(--transition);
z-index: 200;
}
[data-theme="light"] .custom-select-menu {
background: rgba(255, 255, 255, 0.98);
}
.custom-select-wrapper.open .custom-select-menu {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.custom-select-item {
padding: 0.65rem 0.7rem;
border-radius: calc(var(--radius-sm) - 2px);
color: var(--text-primary);
cursor: pointer;
font-size: 0.9rem;
}
.custom-select-item:hover:not(.disabled),
.custom-select-item.selected {
background: var(--bg-hover);
color: var(--accent-hover);
}
.custom-select-item.disabled {
cursor: not-allowed;
opacity: 0.45;
}
.settings-modal-overlay {
position: fixed;
inset: 0;
z-index: 1000;
display: none;
align-items: center;
justify-content: center;
padding: 1.25rem;
background: rgba(2, 6, 23, 0.64);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}
.settings-modal-overlay.open {
display: flex;
}
.settings-modal-card {
width: min(100%, 460px);
border: 1px solid var(--bg-card-border);
border-radius: var(--radius-md);
background: var(--bg-primary);
box-shadow: 0 24px 70px rgba(0, 0, 0, 0.42);
padding: 1.25rem;
}
.settings-modal-subtitle {
margin-top: 0.35rem;
color: var(--text-secondary);
font-size: 0.9rem;
line-height: 1.45;
}
.settings-modal-close {
width: 36px;
height: 36px;
border: 1px solid var(--bg-card-border);
border-radius: var(--radius-sm);
background: var(--bg-input);
color: var(--text-secondary);
font-size: 1.3rem;
line-height: 1;
cursor: pointer;
transition: color var(--transition), border-color var(--transition), background var(--transition);
}
.settings-modal-close:hover,
.settings-modal-close:focus {
border-color: rgba(239, 68, 68, 0.45);
background: rgba(239, 68, 68, 0.12);
color: var(--error);
}
.settings-modal-form {
display: grid;
gap: 1rem;
margin-top: 1.2rem;
}
.settings-modal-actions {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
}
@media (max-width: 1180px) {
.settings-grid,
.settings-form {
grid-template-columns: 1fr;
}
.settings-form .btn {
width: fit-content;
}
.scope-header-actions {
justify-content: flex-start;
}
}
@media (max-width: 640px) {
.settings-header-row,
.card-header-row {
align-items: flex-start;
flex-direction: column;
}
.settings-header-row .btn,
.card-header-row .btn,
.settings-form .btn {
width: 100%;
}
}
.settings-modal-close.btn-icon-sm {
width: 32px !important;
height: 32px !important;
min-height: 32px !important;
padding: 0 !important;
border-radius: var(--button-radius) !important;
}