Raiju/css/raiju-admin-components.css
2026-10-25 06:05:42 +03:00

632 lines
15 KiB
CSS

/*
* Raiju Admin — Unified Component Library
* All classes prefixed with rj- to avoid collision with frontend site CSS.
* Requires: raiju-admin-tokens.css
*/
/* ============================================================
ADMIN SURFACES
============================================================ */
.rj-admin-panel,
.rj-admin-group,
.rj-admin-item {
color: var(--rj-text);
border: 1px solid var(--rj-border);
box-shadow: none;
}
.rj-admin-panel {
background: var(--rj-surface-panel, var(--rj-bg-elevated));
border-radius: var(--rj-radius-lg);
padding: var(--rj-space-5) var(--rj-space-6);
}
.rj-admin-group {
background: var(--rj-surface-group, color-mix(in srgb, var(--rj-bg-elevated) 88%, var(--rj-bg)));
border-radius: var(--rj-radius-lg);
padding: var(--rj-space-4) var(--rj-space-5);
}
.rj-admin-item {
background: var(--rj-surface-item, var(--rj-bg));
border-radius: var(--rj-radius-md);
padding: var(--rj-space-3);
}
.rj-admin-toolbar {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--rj-space-2);
}
.rj-admin-icon-button {
display: inline-flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
padding: 0;
border: 1px solid var(--rj-border);
border-radius: var(--rj-radius-md);
background: var(--rj-bg-elevated);
color: var(--rj-text-muted);
cursor: pointer;
transition: background-color var(--rj-duration-fast) var(--rj-ease),
border-color var(--rj-duration-fast) var(--rj-ease),
color var(--rj-duration-fast) var(--rj-ease),
transform var(--rj-duration-fast) var(--rj-ease);
}
.rj-admin-icon-button:hover,
.rj-admin-icon-button:focus-visible {
background: var(--rj-bg-hover);
border-color: var(--rj-border-strong);
color: var(--rj-text);
outline: none;
}
.rj-admin-icon-button:focus-visible {
box-shadow: 0 0 0 3px var(--rj-focus-ring, var(--rj-primary-muted));
}
.rj-admin-icon-button:active {
transform: scale(0.98);
}
.rj-admin-icon-button svg {
width: 16px;
height: 16px;
stroke-width: 1.5;
}
/* ============================================================
BUTTONS
============================================================ */
.rj-btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--rj-space-2);
height: var(--rj-control-h, 2.5rem);
padding: 0 var(--rj-space-5, 1.25rem);
border: 1px solid transparent;
border-radius: var(--editor-btn-radius, var(--rj-radius-md));
font-family: var(--rj-font-sans);
font-size: var(--rj-text-md, 0.875rem);
font-weight: 500;
line-height: 1.2;
cursor: pointer;
transition: background-color var(--rj-duration-fast) var(--rj-ease),
color var(--rj-duration-fast) var(--rj-ease),
border-color var(--rj-duration-fast) var(--rj-ease),
transform var(--rj-duration-fast) var(--rj-ease),
box-shadow var(--rj-duration-fast) var(--rj-ease);
text-decoration: none;
white-space: nowrap;
user-select: none;
}
.rj-btn:active {
transform: scale(0.98);
}
.rj-btn:focus-visible {
outline: 2px solid var(--rj-primary);
outline-offset: 2px;
}
.rj-btn:disabled {
opacity: 0.5;
pointer-events: none;
}
/* Primary */
/* Same hover as .btn-primary in admin/style.css: lift, then settle; glow is a sheen
plus shadow that .rj-flat-buttons removes */
.rj-btn--primary {
--rj-hover-from: var(--rj-primary);
--rj-hover-peak: var(--rj-hover-lift, var(--rj-primary-hover));
--rj-hover-to: var(--rj-hover-settle, var(--rj-primary-hover));
background-color: var(--rj-primary);
background-image: var(--rj-primary-sheen, none);
color: var(--rj-text-on-primary);
text-shadow: 0 1px 1px rgba(255,255,255,0.25), 0 -1px 1px rgba(0,0,0,0.15);
box-shadow: 0 2px 8px color-mix(in srgb, var(--rj-primary) 15%, transparent);
transition: background-color var(--rj-duration-hover-out, 320ms) ease-out,
box-shadow var(--rj-duration-hover-out, 320ms) ease-out,
transform var(--rj-duration-fast) var(--rj-ease);
}
.rj-btn--primary:hover {
background-color: var(--rj-hover-settle, var(--rj-primary-hover));
box-shadow: 0 4px 20px color-mix(in srgb, var(--rj-primary) 35%, transparent);
animation: rj-hover-fill var(--rj-duration-hover-in, 1400ms) linear both;
transition: box-shadow calc(var(--rj-duration-hover-in, 1400ms) * 0.4) var(--rj-ease),
transform var(--rj-duration-fast) var(--rj-ease);
}
.rj-btn--primary:active {
background-color: var(--rj-primary-active);
animation: none;
transition-duration: var(--rj-duration-press, 100ms);
}
.rj-flat-buttons .rj-btn--primary,
.rj-flat-buttons .rj-btn--primary:hover,
.rj-flat-buttons .rj-btn--primary:active {
background-image: none;
box-shadow: none;
text-shadow: none;
}
.rj-btn:disabled,
.rj-btn[aria-busy="true"] {
animation: none;
pointer-events: none;
}
@keyframes rj-hover-fill {
0% { background-color: var(--rj-hover-from); }
36% { background-color: var(--rj-hover-peak); }
62% { background-color: var(--rj-hover-peak); }
100% { background-color: var(--rj-hover-to); }
}
/* Secondary */
.rj-btn--secondary {
background: var(--rj-bg-sunken);
color: var(--rj-text);
border-color: var(--rj-border);
}
.rj-btn--secondary:hover {
background: var(--rj-bg-hover);
border-color: var(--rj-border-strong);
}
/* Ghost */
.rj-btn--ghost {
background: transparent;
color: var(--rj-text-secondary);
}
.rj-btn--ghost:hover {
background: var(--rj-bg-hover);
color: var(--rj-text);
}
/* Danger */
.rj-btn--danger {
background: var(--rj-danger);
color: #ffffff;
}
.rj-btn--danger:hover {
background: var(--rj-danger-hover);
}
/* Success */
.rj-btn--success {
background: var(--rj-success);
color: #ffffff;
}
.rj-btn--success:hover {
background: #15803d;
}
/* Icon-only button */
.rj-btn--icon {
width: var(--rj-control-h, 2.5rem);
height: var(--rj-control-h, 2.5rem);
padding: 0;
border-radius: var(--editor-btn-radius, var(--rj-radius-md));
}
/* Sizes */
.rj-btn--sm {
height: var(--rj-control-h-sm, 2rem);
padding: 0 var(--rj-space-3, 0.75rem);
font-size: var(--rj-text-sm, 0.8125rem);
}
.rj-btn--sm.rj-btn--icon {
width: var(--rj-control-h-sm, 2rem);
}
.rj-btn--block {
display: flex;
width: 100%;
}
/* ============================================================
FORM FIELDS
============================================================ */
.rj-field {
margin-bottom: var(--rj-space-5);
}
.rj-field__label {
display: block;
margin-bottom: var(--rj-space-2);
font-family: var(--rj-font-sans);
font-size: 0.875rem;
font-weight: 500;
color: var(--rj-text);
}
.rj-field__label--optional {
font-weight: 400;
color: var(--rj-text-muted);
}
.rj-field__input,
.rj-field__textarea,
.rj-field__select {
width: 100%;
padding: 10px 14px;
border: 1px solid var(--rj-border);
border-radius: var(--rj-radius-md);
background: var(--rj-bg-elevated);
color: var(--rj-text);
font-family: var(--rj-font-sans);
font-size: 0.9375rem;
line-height: 1.5;
transition: border-color var(--rj-duration-fast) var(--rj-ease),
box-shadow var(--rj-duration-fast) var(--rj-ease);
}
.rj-field__input::placeholder,
.rj-field__textarea::placeholder {
color: var(--rj-text-muted);
}
.rj-field__input:focus,
.rj-field__textarea:focus,
.rj-field__select:focus {
outline: none;
border-color: var(--rj-primary);
box-shadow: 0 0 0 3px var(--rj-primary-muted);
}
.rj-field__textarea {
min-height: 80px;
resize: vertical;
}
.rj-field__select {
appearance: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5l5 5 5-5' stroke='%23525252' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 12px center;
padding-right: 40px;
}
.rj-field__hint {
display: block;
margin-top: var(--rj-space-1);
font-family: var(--rj-font-sans);
font-size: 0.8125rem;
color: var(--rj-text-muted);
line-height: 1.4;
}
.rj-field__hint code {
background: var(--rj-bg-sunken);
padding: 1px 5px;
border-radius: var(--rj-radius-sm);
font-family: var(--rj-font-mono);
font-size: 0.8em;
}
.rj-field__error {
display: block;
margin-top: var(--rj-space-1);
font-family: var(--rj-font-sans);
font-size: 0.8125rem;
color: var(--rj-danger);
line-height: 1.4;
}
/* ============================================================
CARDS
============================================================ */
.rj-card {
background: var(--rj-bg-elevated);
border: 1px solid var(--rj-border);
border-radius: var(--rj-radius-lg);
box-shadow: none;
}
.rj-card__header {
padding: var(--rj-space-5) var(--rj-space-6);
border-bottom: 1px solid var(--rj-border);
display: flex;
align-items: center;
justify-content: space-between;
}
.rj-card__header h2,
.rj-card__header h3 {
margin: 0;
font-family: var(--rj-font-sans);
font-weight: 600;
color: var(--rj-text);
}
.rj-card__body {
padding: var(--rj-space-5) var(--rj-space-6);
}
.rj-card--flat {
box-shadow: none;
}
/* ============================================================
TABS (Pill-style)
============================================================ */
.rj-tabs {
display: flex;
align-items: center;
gap: var(--rj-space-1);
}
.rj-tab {
position: relative;
padding: 8px 16px;
border: none;
border-radius: var(--rj-radius-full);
background: transparent;
color: var(--rj-text-secondary);
font-family: var(--rj-font-sans);
font-size: 0.875rem;
font-weight: 500;
cursor: pointer;
transition: background-color var(--rj-duration-fast) var(--rj-ease),
color var(--rj-duration-fast) var(--rj-ease);
white-space: nowrap;
}
.rj-tab:hover {
background: var(--rj-bg-hover);
color: var(--rj-text);
}
.rj-tab:focus-visible {
outline: 2px solid var(--rj-primary);
outline-offset: 2px;
}
.rj-tab--active {
background: var(--rj-primary-subtle);
color: var(--rj-primary);
}
.rj-tab--active:hover {
background: var(--rj-primary-muted);
}
/* ============================================================
BADGE
============================================================ */
.rj-badge {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 18px;
height: 18px;
padding: 0 5px;
border-radius: var(--rj-radius-full);
background: var(--rj-danger);
color: #ffffff;
font-family: var(--rj-font-sans);
font-size: 0.6875rem;
font-weight: 600;
line-height: 1;
}
/* ============================================================
MODALS
============================================================ */
.rj-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: var(--rj-z-modal);
display: none;
}
.rj-modal.active {
display: block;
}
.rj-modal__backdrop {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
animation: rj-fade-in var(--rj-duration-normal) var(--rj-ease);
}
.rj-modal__dialog {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: var(--rj-bg-elevated);
border-radius: var(--rj-radius-lg);
box-shadow: var(--rj-shadow-xl);
width: 90%;
max-width: 550px;
max-height: 90vh;
display: flex;
flex-direction: column;
overflow: hidden;
animation: rj-slide-in var(--rj-duration-normal) var(--rj-ease);
}
.rj-modal--sm .rj-modal__dialog { max-width: 400px; }
.rj-modal--lg .rj-modal__dialog { max-width: 700px; }
.rj-modal--xl .rj-modal__dialog { max-width: 900px; }
.rj-modal__header {
padding: var(--rj-space-4) var(--rj-space-5);
border-bottom: 1px solid var(--rj-border);
display: flex;
align-items: center;
justify-content: space-between;
}
.rj-modal__header h3 {
margin: 0;
font-family: var(--rj-font-sans);
font-size: 1.125rem;
font-weight: 600;
color: var(--rj-text);
}
.rj-modal__close {
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border: none;
border-radius: var(--rj-radius-md);
background: transparent;
color: var(--rj-text-muted);
font-size: 1.25rem;
cursor: pointer;
transition: background-color var(--rj-duration-fast) var(--rj-ease),
color var(--rj-duration-fast) var(--rj-ease);
}
.rj-modal__close:hover {
background: var(--rj-bg-hover);
color: var(--rj-text);
}
.rj-modal__body {
padding: var(--rj-space-5);
overflow-y: auto;
flex: 1;
}
.rj-modal__footer {
display: flex;
justify-content: flex-end;
gap: var(--rj-space-2);
padding: var(--rj-space-4) var(--rj-space-5);
border-top: 1px solid var(--rj-border);
background: var(--rj-bg-sunken);
border-radius: 0 0 var(--rj-radius-lg) var(--rj-radius-lg);
}
/* ============================================================
TOASTS
============================================================ */
.rj-toast {
position: fixed;
bottom: var(--rj-space-5);
right: var(--rj-space-5);
z-index: var(--rj-z-toast);
display: flex;
align-items: center;
gap: var(--rj-space-3);
padding: var(--rj-space-3) var(--rj-space-5);
background: var(--rj-bg-elevated);
border: 1px solid var(--rj-border);
border-left: 4px solid var(--rj-primary);
border-radius: var(--rj-radius-md);
box-shadow: var(--rj-shadow-lg);
color: var(--rj-text);
font-family: var(--rj-font-sans);
font-size: 0.875rem;
animation: rj-slide-in-right var(--rj-duration-normal) var(--rj-ease);
}
.rj-toast--success {
border-left-color: var(--rj-success);
}
.rj-toast--error {
border-left-color: var(--rj-danger);
}
.rj-toast--info {
border-left-color: var(--rj-primary);
}
/* ============================================================
ALERTS / MESSAGES
============================================================ */
.rj-alert {
padding: var(--rj-space-3) var(--rj-space-4);
border-radius: var(--rj-radius-md);
font-family: var(--rj-font-sans);
font-size: 0.875rem;
line-height: 1.5;
margin-bottom: var(--rj-space-5);
}
.rj-alert--error {
background: var(--rj-danger-subtle);
color: var(--rj-danger);
border: 1px solid rgba(220, 38, 38, 0.15);
}
.rj-alert--success {
background: var(--rj-success-subtle);
color: var(--rj-success);
border: 1px solid rgba(22, 163, 74, 0.15);
}
.rj-alert--warning {
background: var(--rj-warning-subtle);
color: var(--rj-warning);
border: 1px solid rgba(217, 119, 6, 0.15);
}
/* ============================================================
ANIMATIONS
============================================================ */
@keyframes rj-fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes rj-slide-in {
from { opacity: 0; transform: translate(-50%, -48%) scale(0.96); }
to { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}
@keyframes rj-slide-in-right {
from { opacity: 0; transform: translateX(100%); }
to { opacity: 1; transform: translateX(0); }
}