Files
3x-ui/frontend/src/pages/clients/ClientsPage.css
T
Sanaei 5008906c4c feat(clients): filter the client list by clicking a summary stat card
Each card on the Clients page now toggles its status bucket as the sole
filter, and the Clients card clears it. The bucket filters used to be
wider than the card counts: "active" still included clients near
depletion and "deactive" included disabled clients that had run out, so
a filtered list could disagree with the number on the card. Both filters
now reuse the summary expressions, and a test pins each card's count to
the size of its filtered list.
2026-09-15 22:06:22 +02:00

335 lines
5.8 KiB
CSS

.clients-page .ant-pagination-options-size-changer,
.clients-page .ant-pagination-options-size-changer .ant-select-selector {
min-width: 100px;
}
.client-email-list {
max-height: 280px;
min-width: 160px;
overflow-y: auto;
padding-right: 4px;
}
.client-email-list > div {
padding: 2px 0;
font-size: 12px;
white-space: nowrap;
}
.client-email-more {
margin-top: 4px;
padding-top: 4px;
border-top: 1px solid var(--ant-color-border-secondary, rgba(128, 128, 128, 0.2));
opacity: 0.65;
}
.filter-bar {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
margin-bottom: 12px;
}
.filter-bar.mobile {
gap: 6px;
margin-bottom: 8px;
}
.filter-bar.mobile > * {
flex: 0 0 auto;
}
.filter-count {
margin-inline-start: auto;
color: var(--ant-color-text-secondary);
font-size: 13px;
white-space: nowrap;
}
.filter-chips {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin: 0 0 12px;
padding: 6px 8px;
background: var(--ant-color-fill-quaternary);
border-radius: 8px;
}
.filter-chips .ant-tag {
margin: 0;
}
.summary-stat {
margin: -4px -8px;
padding: 4px 8px;
border-radius: 8px;
cursor: pointer;
transition: background-color 120ms ease;
}
.summary-stat:hover,
.summary-stat:focus-visible {
background: var(--ant-color-fill-tertiary);
}
.summary-stat.selected {
background: var(--ant-color-primary-bg);
}
.dot {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 4px;
vertical-align: middle;
}
.dot-green {
background: var(--ant-color-success);
}
.dot-blue {
background: var(--ant-color-primary);
}
.dot-red {
background: var(--ant-color-error);
}
.dot-orange {
background: var(--ant-color-warning);
}
.dot-gray {
background: var(--ant-color-text-quaternary);
}
.status-tag {
margin: 0 0 0 4px;
font-size: 11px;
padding: 0 6px;
line-height: 18px;
}
.external-link-card {
display: flex;
flex-direction: column;
gap: 10px;
margin-bottom: 12px;
padding: 10px;
border: 1px solid var(--ant-color-border-secondary);
border-radius: 6px;
background: var(--ant-color-fill-quaternary);
}
.external-link-row {
display: flex;
align-items: center;
gap: 10px;
}
.external-link-row .ant-input {
flex: 1;
min-width: 0;
}
.external-link-enable {
display: inline-flex;
align-items: center;
gap: 6px;
min-width: 78px;
color: var(--ant-color-text-secondary);
white-space: nowrap;
}
.external-link-details {
display: grid;
gap: 10px;
}
.external-link-details.two-cols {
grid-template-columns: minmax(0, 1fr) minmax(220px, 0.8fr);
}
.external-link-details.three-cols {
grid-template-columns: minmax(0, 1fr) minmax(160px, 0.8fr) minmax(220px, 0.8fr);
}
.external-link-fetch-status {
font-size: 12px;
line-height: 1.4;
overflow-wrap: anywhere;
}
@media (max-width: 640px) {
.external-link-row {
align-items: stretch;
flex-wrap: wrap;
}
.external-link-enable {
width: 100%;
}
.external-link-row .ant-input {
flex-basis: calc(100% - 44px);
}
.external-link-details.two-cols,
.external-link-details.three-cols {
grid-template-columns: 1fr;
}
}
.card-toolbar {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
padding: 6px 0;
}
@media (min-width: 769px) and (max-width: 920px) {
.card-toolbar {
gap: 6px;
}
.card-toolbar .ant-btn .ant-btn-icon + span,
.card-toolbar .ant-btn > span:not(.ant-btn-icon):not(.ant-tag):not(.anticon) {
display: none;
}
.card-toolbar .ant-btn {
padding-inline: 8px;
}
}
.email-cell {
display: flex;
flex-direction: column;
}
.email-cell .email {
font-weight: 500;
}
.email-cell .sub {
font-size: 11px;
opacity: 0.55;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 220px;
}
.client-cards {
display: flex;
flex-direction: column;
gap: 10px;
margin-top: 4px;
}
.card-bulk-bar {
display: flex;
align-items: center;
gap: 8px;
padding: 4px 4px 8px;
}
.card-pagination {
display: flex;
justify-content: center;
flex-wrap: wrap;
padding: 4px 0 8px;
}
.card-pagination .ant-pagination-options-size-changer,
.card-pagination .ant-pagination-options-size-changer .ant-select-selector {
min-width: 88px;
}
.bulk-count {
font-size: 12px;
background: color-mix(in srgb, var(--ant-color-primary) 12%, transparent);
color: var(--ant-color-primary);
padding: 1px 8px;
border-radius: 10px;
}
.client-card {
border: 1px solid var(--ant-color-border-secondary);
border-radius: 10px;
padding: 10px 12px;
background: var(--ant-color-fill-quaternary);
}
.client-card.is-selected {
border-color: var(--ant-color-primary);
background: color-mix(in srgb, var(--ant-color-primary) 6%, transparent);
}
.client-card-comment {
display: block;
margin-top: 6px;
color: var(--ant-color-text-secondary);
font-size: 12px;
max-height: 4.5em;
overflow-y: auto;
overflow-wrap: anywhere;
white-space: pre-wrap;
}
.client-card-speed {
margin-top: 6px;
font-size: 12px;
color: var(--ant-color-text-secondary);
}
.card-head {
display: flex;
align-items: center;
gap: 8px;
user-select: none;
}
.card-head .tag-name {
font-weight: 600;
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.card-actions {
display: flex;
align-items: center;
gap: 10px;
flex-shrink: 0;
}
.row-action-trigger {
font-size: 18px;
cursor: pointer;
opacity: 0.75;
transition: opacity 120ms ease;
}
.row-action-trigger:hover {
opacity: 1;
}
.card-empty {
text-align: center;
padding: 40px 16px;
color: var(--ant-color-text-secondary);
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
.clients-empty {
padding: 32px 0;
text-align: center;
color: var(--ant-color-text-secondary);
}