rpki/ui/rpki-explorer/src/styles/components.css

629 lines
11 KiB
CSS

/* Shared UI components: cards, tables, pills, buttons, banners, tabs, forms. */
.panel {
background: var(--bg-1);
border: 1px solid var(--border);
border-radius: var(--radius-l);
box-shadow: var(--shadow-1);
min-width: 0;
}
.panel-header {
display: flex;
align-items: center;
gap: var(--space-3);
padding: var(--space-3) var(--space-4);
border-bottom: 1px solid var(--border);
flex-wrap: wrap;
}
.panel-header h2 {
font-size: 13.5px;
font-weight: 650;
}
.panel-header .panel-subtitle {
font-size: 12px;
color: var(--text-2);
}
.panel-header .panel-tools {
margin-left: auto;
display: flex;
align-items: center;
gap: var(--space-2);
flex-wrap: wrap;
}
.panel-body {
padding: var(--space-4);
}
.panel-body.flush {
padding: 0;
}
/* Buttons */
.btn {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 12px;
border: 1px solid var(--border-strong);
border-radius: var(--radius-m);
background: var(--bg-1);
color: var(--text-1);
font-size: 12.5px;
font-weight: 550;
cursor: pointer;
white-space: nowrap;
transition:
background var(--transition-fast),
border-color var(--transition-fast);
}
.btn:hover:not(:disabled) {
background: var(--bg-2);
text-decoration: none;
}
.btn:disabled {
opacity: 0.55;
cursor: not-allowed;
}
.btn.primary {
background: var(--blue-600);
border-color: var(--blue-600);
color: #fff;
}
.btn.primary:hover:not(:disabled) {
background: var(--blue-500);
}
.btn.danger {
color: var(--red-700);
border-color: var(--red-100);
background: var(--red-050);
}
.btn.small {
padding: 3px 8px;
font-size: 12px;
border-radius: var(--radius-s);
}
/* Status pill */
.pill {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 1px 8px;
border-radius: 999px;
font-size: 11.5px;
font-weight: 600;
line-height: 18px;
white-space: nowrap;
border: 1px solid transparent;
}
.pill .pill-dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: currentColor;
flex: none;
}
.pill.tone-green {
background: var(--green-050);
color: var(--green-700);
border-color: var(--green-100);
}
.pill.tone-amber {
background: var(--amber-050);
color: var(--amber-700);
border-color: var(--amber-100);
}
.pill.tone-red {
background: var(--red-050);
color: var(--red-700);
border-color: var(--red-100);
}
.pill.tone-blue {
background: var(--blue-050);
color: var(--blue-700);
border-color: var(--blue-100);
}
.pill.tone-slate {
background: var(--slate-100);
color: var(--text-2);
border-color: var(--slate-200);
}
/* Data table */
.table-wrap {
overflow-x: auto;
border-radius: 0 0 var(--radius-l) var(--radius-l);
/* Scroll shadows hint at horizontally clipped columns (narrow viewports). */
background:
linear-gradient(to right, var(--bg-1) 30%, transparent),
linear-gradient(to left, var(--bg-1) 30%, transparent),
radial-gradient(farthest-side at 0 50%, rgba(15, 23, 42, 0.14), transparent),
radial-gradient(farthest-side at 100% 50%, rgba(15, 23, 42, 0.14), transparent);
background-repeat: no-repeat;
background-size:
40px 100%,
40px 100%,
12px 100%,
12px 100%;
background-attachment: local, local, scroll, scroll;
}
table.data-table {
width: 100%;
border-collapse: collapse;
font-size: 12.8px;
}
.data-table th {
text-align: left;
font-size: 11px;
font-weight: 650;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-2);
padding: 8px var(--space-3);
border-bottom: 1px solid var(--border);
background: var(--bg-2);
white-space: nowrap;
position: sticky;
top: 0;
z-index: 1;
}
.data-table td {
padding: 7px var(--space-3);
border-bottom: 1px solid var(--border);
vertical-align: top;
}
.data-table tbody tr:last-child td {
border-bottom: none;
}
.data-table tbody tr.clickable {
cursor: pointer;
}
.data-table tbody tr.clickable:hover {
background: var(--blue-050);
}
.data-table td.num,
.data-table th.num {
text-align: right;
font-variant-numeric: tabular-nums;
}
.data-table .cell-main {
font-weight: 550;
}
.table-state {
padding: var(--space-6);
text-align: center;
color: var(--text-2);
}
/* KPI cards */
.kpi-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: var(--space-3);
}
.kpi-card {
background: var(--bg-1);
border: 1px solid var(--border);
border-radius: var(--radius-l);
padding: var(--space-3) var(--space-4);
box-shadow: var(--shadow-1);
display: flex;
flex-direction: column;
gap: 2px;
min-width: 0;
color: inherit;
}
.kpi-card .kpi-label {
font-size: 11px;
font-weight: 650;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-2);
}
.kpi-card .kpi-value {
font-size: 22px;
font-weight: 680;
font-variant-numeric: tabular-nums;
line-height: 1.2;
}
.kpi-card .kpi-sub {
font-size: 11.5px;
color: var(--text-3);
}
.kpi-card.tone-red .kpi-value {
color: var(--red-700);
}
.kpi-card.tone-amber .kpi-value {
color: var(--amber-700);
}
.kpi-card.tone-blue .kpi-value {
color: var(--blue-700);
}
a.kpi-card:hover {
text-decoration: none;
border-color: var(--blue-500);
}
/* Banners and state blocks */
.banner {
display: flex;
align-items: flex-start;
gap: var(--space-3);
padding: var(--space-3) var(--space-4);
border-radius: var(--radius-m);
border: 1px solid;
font-size: 12.8px;
}
.banner.error {
background: var(--red-050);
border-color: var(--red-100);
color: var(--red-700);
}
.banner.warning {
background: var(--amber-050);
border-color: var(--amber-100);
color: var(--amber-700);
}
.banner.info {
background: var(--blue-050);
border-color: var(--blue-100);
color: var(--blue-700);
}
.banner .banner-body {
flex: 1;
min-width: 0;
overflow-wrap: anywhere;
}
.state-block {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: var(--space-2);
padding: var(--space-8) var(--space-4);
color: var(--text-2);
text-align: center;
}
.state-block .state-title {
font-weight: 600;
color: var(--text-1);
}
.spinner {
width: 18px;
height: 18px;
border: 2px solid var(--border);
border-top-color: var(--blue-500);
border-radius: 50%;
animation: spin 0.8s linear infinite;
flex: none;
}
.spinner.small {
width: 13px;
height: 13px;
border-width: 1.5px;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
/* Tabs */
.tabs {
display: flex;
gap: 2px;
border-bottom: 1px solid var(--border);
overflow-x: auto;
}
.tabs [role="tab"] {
padding: 8px 14px;
border: none;
background: none;
font-size: 13px;
font-weight: 550;
color: var(--text-2);
cursor: pointer;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
white-space: nowrap;
}
.tabs [role="tab"]:hover {
color: var(--text-1);
}
.tabs [role="tab"][aria-selected="true"] {
color: var(--blue-700);
border-bottom-color: var(--blue-600);
}
/* Filter bar */
.filter-bar {
display: flex;
align-items: flex-end;
gap: var(--space-3);
flex-wrap: wrap;
}
.filter-field {
display: flex;
flex-direction: column;
gap: 3px;
min-width: 0;
}
.filter-field > label {
font-size: 11px;
font-weight: 650;
text-transform: uppercase;
letter-spacing: 0.04em;
color: var(--text-2);
}
.filter-field input[type="text"],
.filter-field input[type="search"],
.filter-field select {
padding: 5px 8px;
border: 1px solid var(--border);
border-radius: var(--radius-m);
background: var(--bg-1);
font-size: 12.5px;
min-width: 140px;
}
.filter-field input.mono {
font-family: var(--font-mono);
font-size: 12px;
}
.filter-check {
display: flex;
align-items: center;
gap: 6px;
padding-bottom: 6px;
font-size: 12.5px;
color: var(--text-1);
cursor: pointer;
}
/* Pager */
.pager {
display: flex;
align-items: center;
gap: var(--space-3);
padding: var(--space-2) var(--space-4);
border-top: 1px solid var(--border);
font-size: 12px;
color: var(--text-2);
flex-wrap: wrap;
}
.pager .pager-info {
margin-right: auto;
}
/* Definition list for metadata */
.meta-grid {
display: grid;
grid-template-columns: minmax(140px, max-content) minmax(0, 1fr);
gap: 6px var(--space-4);
font-size: 12.8px;
}
.meta-grid dt {
color: var(--text-2);
font-weight: 550;
white-space: nowrap;
}
.meta-grid dd {
margin: 0;
min-width: 0;
overflow-wrap: anywhere;
}
/* Copyable value */
.copyable {
display: inline-flex;
align-items: center;
gap: 5px;
min-width: 0;
max-width: 100%;
}
.copyable .copyable-text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-family: var(--font-mono);
font-size: 0.94em;
}
.copyable .copy-btn {
display: inline-flex;
align-items: center;
border: none;
background: none;
padding: 2px;
color: var(--text-3);
cursor: pointer;
border-radius: var(--radius-s);
flex: none;
}
.copyable .copy-btn:hover {
color: var(--blue-600);
background: var(--blue-050);
}
.copyable .copy-btn.copied {
color: var(--green-600);
}
/* Chips */
.chip {
display: inline-flex;
align-items: center;
padding: 1px 8px;
border-radius: 999px;
background: var(--slate-100);
border: 1px solid var(--slate-200);
font-size: 11.5px;
font-family: var(--font-mono);
white-space: nowrap;
}
.chip-list {
display: flex;
flex-wrap: wrap;
gap: 6px;
}
/* Clickable expand/collapse toggle inside an ExpandableChipList. */
button.chip-more {
cursor: pointer;
color: var(--blue-700);
border-style: dashed;
background: transparent;
}
button.chip-more:hover {
background: var(--slate-100);
}
/* JSON block */
.json-block {
background: var(--text-1);
color: #d7e0ee;
border-radius: var(--radius-m);
padding: var(--space-3) var(--space-4);
font-family: var(--font-mono);
font-size: 12px;
line-height: 1.5;
overflow-x: auto;
white-space: pre;
margin: 0;
}
/* Skeleton loading rows */
.skeleton-row {
height: 14px;
border-radius: var(--radius-s);
background: linear-gradient(90deg, var(--bg-2) 25%, var(--bg-3) 50%, var(--bg-2) 75%);
background-size: 200% 100%;
animation: shimmer 1.2s infinite;
margin: 10px var(--space-3);
}
@keyframes shimmer {
0% {
background-position: 200% 0;
}
100% {
background-position: -200% 0;
}
}
/* Workflow (async job) status line */
.workflow-status {
display: flex;
align-items: center;
gap: var(--space-2);
font-size: 12.5px;
color: var(--text-2);
flex-wrap: wrap;
}
/* Search result groups */
.result-group h3 {
font-size: 12px;
font-weight: 650;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-2);
margin-bottom: var(--space-2);
}
.result-item {
display: flex;
align-items: center;
gap: var(--space-3);
padding: 8px var(--space-3);
border: 1px solid var(--border);
border-radius: var(--radius-m);
background: var(--bg-1);
margin-bottom: 6px;
min-width: 0;
}
.result-item:hover {
border-color: var(--blue-500);
text-decoration: none;
}
.result-item .result-kind {
flex: none;
width: 88px;
}
.result-item .result-main {
min-width: 0;
flex: 1;
}
.result-item .result-title {
font-family: var(--font-mono);
font-size: 12.3px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.result-item .result-sub {
font-size: 11.5px;
color: var(--text-3);
}