1
0

refactor(admin-lists): slim tenant + user grids, Stripe-style pagination

Tenant list:
- Drop the avatar/logo column — the list now shows only Tenant name
  and user count. Also drop the logo-hasLogo server lookup and the
  initials/placeholder markup.

User list (13 → 4 columns, Stripe pattern):
- User (compound: avatar + Name + email subtitle, click opens drawer)
- Tenants (badges, primary tooltip)
- Last login (relative badge)
- State (active/inactive badge)
- UUID hidden at the last column for cells[uuidIndex].data
- Everything else (departments, roles, phone, mobile, short_dial,
  created, modified) lives in the detail drawer.
- Document the off-by-one gotcha: with row selection enabled gridjs
  prepends a checkbox cell, so runtime cells[] are shifted by +1;
  uuidIndex is 5 (column position 4 + selection offset).
- New .grid-user-profile css mirrors .grid-tenant-profile (avatar +
  stacked name/email) with ellipsis and primary-color hover affordance.

Pagination (all Grid.js lists):
- Non-current page buttons now use the neutral-chip secondary-outline
  tokens (--app-button-neutral-*) plus the raised box-shadow — matches
  the rest of the button system in both light and dark themes.
- Current page stays distinctly primary-filled with the filled-shadow;
  focus-visible combines the chip shadow with the primary focus ring.
- Disabled pager buttons remain neutral but lose the lift shadow.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-24 21:52:44 +02:00
parent fa86009e3f
commit 874a90d8f8
6 changed files with 117 additions and 129 deletions

View File

@@ -248,12 +248,15 @@
same custom properties, not by setting `color`/`background-color`
directly, and we must use a token that isn't shadowed inside the button
scope (`--app-form-element-color` fits). */
/* Align pagination buttons with the Stripe-style neutral-chip secondary
outline: theme-aware surface, high-contrast text, subtle border,
raised shadow. Current page stays distinct via primary fill. */
.gridjs-pagination .gridjs-pages button,
.gridjs-pagination .gridjs-pages button[type="button"] {
--app-background-color: var(--app-form-element-background-color);
--app-color: var(--app-form-element-color);
--app-border-color: var(--app-table-border-color);
--app-box-shadow: none;
--app-background-color: var(--app-button-neutral-bg);
--app-color: var(--app-button-neutral-color);
--app-border-color: var(--app-button-neutral-border);
box-shadow: var(--app-button-neutral-shadow);
margin: 0;
display: inline-flex;
align-items: center;
@@ -263,21 +266,24 @@
line-height: 1.3;
min-width: 2rem;
white-space: nowrap;
font-weight: 500;
font-weight: var(--font-medium);
}
.gridjs-pagination .gridjs-pages button:hover:not(:disabled),
.gridjs-pagination .gridjs-pages button[type="button"]:hover:not(:disabled),
.gridjs-pagination .gridjs-pages button:focus:not(:disabled),
.gridjs-pagination .gridjs-pages button[type="button"]:focus:not(:disabled) {
--app-background-color: var(--app-primary-hover-background);
--app-border-color: var(--app-primary-hover-border);
--app-color: var(--app-primary-inverse);
--app-background-color: var(--app-button-neutral-bg-hover);
--app-color: var(--app-button-neutral-color-hover);
--app-border-color: var(--app-button-neutral-border-hover);
box-shadow: var(--app-button-neutral-shadow-hover);
}
.gridjs-pagination .gridjs-pages button:focus-visible {
outline: none;
box-shadow: 0 0 0 var(--app-outline-width) var(--app-primary-focus);
box-shadow:
var(--app-button-neutral-shadow),
0 0 0 var(--app-outline-width) var(--app-primary-focus);
}
.gridjs-pagination .gridjs-pages button.gridjs-currentPage,
@@ -287,16 +293,18 @@
--app-background-color: var(--app-primary);
--app-border-color: var(--app-primary);
--app-color: var(--app-primary-inverse);
font-weight: 600;
box-shadow: var(--app-button-filled-shadow);
font-weight: var(--font-semibold);
}
.gridjs-pagination .gridjs-pages button:disabled,
.gridjs-pagination .gridjs-pages button[disabled] {
--app-background-color: var(--app-background-color);
--app-background-color: var(--app-button-neutral-bg);
--app-color: var(--app-muted-color);
--app-border-color: var(--app-table-border-color);
--app-border-color: var(--app-button-neutral-border);
box-shadow: none;
cursor: default;
opacity: 0.7;
opacity: 0.55;
}
.gridjs-pagination .gridjs-pages button.gridjs-spread,
@@ -634,6 +642,42 @@
font-weight: 500;
}
/* Compound user cell: avatar + name (strong) + email subtitle (small, muted). */
.grid-user-profile {
display: inline-flex;
align-items: center;
gap: 0.75rem;
min-width: 0;
}
.grid-user-profile-text {
display: inline-flex;
flex-direction: column;
min-width: 0;
line-height: var(--leading-tight);
}
.grid-user-profile-text strong {
font-weight: var(--font-medium);
color: var(--app-color);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.grid-user-profile-text small {
font-size: var(--text-xs);
color: var(--app-muted-color);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
a.grid-user-profile.app-grid-link-cell:hover .grid-user-profile-text strong {
color: var(--app-primary);
text-decoration: underline;
}
.gridjs-container .grid-actions {
display: inline-flex;
align-items: center;
@@ -664,6 +708,7 @@
.gridjs-td .badge,
.gridjs-td .grid-name-cell,
.gridjs-td .grid-tenant-profile,
.gridjs-td .grid-user-profile,
.gridjs-td .app-inline-actions {
white-space: nowrap;
}