PlanTempusApp/PlanTempus.Application/wwwroot/css/components.css
Janus C. H. Knudsen 679c3fb3a6 Refactor employee table and row components
Migrates custom table components to generic data table
Improves consistency in table and row implementations
Removes legacy custom table elements in favor of more flexible data table approach
2026-01-14 16:53:42 +01:00

753 lines
16 KiB
CSS

/**
* UI Components - Shared reusable components
*
* This file contains all shared UI components used across the application.
* Feature files should NOT define these components - only use them.
*
* Components:
* - swp-btn (buttons)
* - swp-status-badge (status/role badges)
* - swp-plan-card (subscription plan cards)
* - swp-avatar (user avatars with size variants)
* - swp-icon-btn (icon-only buttons)
* - swp-card (content cards with section-label/footer)
* - swp-section-label (card section headers)
* - swp-section-header (section header with action link)
* - swp-section-action (action link in section header)
* - swp-add-button (dashed border add button)
* - BASE PATTERNS: table, list-item, icon-container (Grid+Subgrid reusable patterns)
*/
/* ===========================================
BASE PATTERNS - Grid + Subgrid Tables
=========================================== */
swp-table-header-base {
display: grid;
grid-column: 1 / -1;
grid-template-columns: subgrid;
background: var(--color-background-alt);
border-bottom: 1px solid var(--color-border);
swp-table-cell-base {
font-size: var(--font-size-xs);
font-weight: var(--font-weight-semibold);
text-transform: uppercase;
letter-spacing: 0.5px;
color: var(--color-text-secondary);
}
}
swp-table-body-base {
display: grid;
grid-column: 1 / -1;
grid-template-columns: subgrid;
}
swp-table-row-base {
display: grid;
grid-column: 1 / -1;
grid-template-columns: subgrid;
align-items: center;
border-bottom: 1px solid var(--color-border);
transition: background var(--transition-fast);
&:last-child {
border-bottom: none;
}
&:hover {
background: var(--color-background-hover);
}
}
/* ===========================================
BASE PATTERNS - List Items (Grid+Subgrid)
=========================================== */
swp-list-base {
display: contents;
}
swp-list-item-base {
display: grid;
grid-column: 1 / -1;
grid-template-columns: subgrid;
align-items: center;
padding: var(--card-padding);
background: var(--color-background-alt);
border-radius: var(--radius-lg);
cursor: pointer;
transition: background var(--transition-fast);
&:hover {
background: var(--color-background-hover);
}
}
/* ===========================================
BASE PATTERNS - Icon Container
=========================================== */
swp-icon-container {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
background: var(--color-background-hover);
border-radius: var(--radius-xl);
color: var(--color-text-secondary);
font-size: var(--font-size-xl);
flex-shrink: 0;
}
/* ===========================================
DATA TABLE (Generic Grid + Subgrid)
grid-template-columns defineres i feature CSS
=========================================== */
swp-data-table {
display: grid;
swp-data-table-header {
display: grid;
grid-column: 1 / -1;
grid-template-columns: subgrid;
background: var(--color-background-alt);
swp-data-table-cell {
font-size: var(--font-size-xs);
font-weight: var(--font-weight-semibold);
text-transform: uppercase;
letter-spacing: 0.5px;
color: var(--color-text-secondary);
padding: var(--spacing-4);
}
}
swp-data-table-row {
display: grid;
grid-column: 1 / -1;
grid-template-columns: subgrid;
align-items: center;
border-bottom: 1px solid var(--color-border);
transition: background var(--transition-fast);
&:last-child {
border-bottom: none;
}
&:hover {
background: var(--color-background-hover);
}
}
swp-data-table-cell {
padding: var(--spacing-4);
font-size: var(--font-size-base);
color: var(--color-text);
&.mono {
font-family: var(--font-mono);
}
&.muted {
color: var(--color-text-muted);
}
&.right {
text-align: right;
}
}
}
/* ===========================================
BUTTONS (swp-btn)
=========================================== */
swp-btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--spacing-2);
padding: var(--spacing-3) var(--spacing-6);
font-size: var(--font-size-base);
font-weight: var(--font-weight-medium);
font-family: var(--font-family);
border-radius: var(--radius-md);
border: 1px solid transparent;
cursor: pointer;
transition: all var(--transition-fast);
text-decoration: none;
& i {
font-size: 18px;
}
/* Primary button */
&.primary {
background: var(--color-teal);
color: white;
border-color: var(--color-teal);
&:hover {
background: #00796b;
border-color: #00796b;
}
&:active {
transform: translateY(1px);
}
&:disabled {
background: var(--color-border);
border-color: var(--color-border);
cursor: not-allowed;
}
}
/* Secondary button */
&.secondary {
background: var(--color-surface);
border: 1px solid var(--color-border);
color: var(--color-text);
&:hover {
background: var(--color-background-hover);
}
}
/* Ghost button */
&.ghost {
background: transparent;
color: var(--color-text-secondary);
&:hover {
color: var(--color-text);
}
}
/* Outline button */
&.outline {
background: transparent;
border: 1px solid var(--color-teal);
color: var(--color-teal);
&:hover {
background: var(--bg-teal-medium);
}
&.purple {
border-color: var(--color-purple);
color: var(--color-purple);
&:hover {
background: var(--bg-purple-medium);
}
}
}
/* Social button */
&.social {
background: var(--color-background);
color: var(--color-text);
border-color: var(--color-border);
&:hover {
background: var(--color-background-hover);
border-color: var(--color-text-muted);
}
& img {
width: 20px;
height: 20px;
}
}
/* Size variants */
&.sm {
padding: var(--spacing-2) var(--spacing-3);
font-size: var(--font-size-xs);
& i {
font-size: 14px;
}
}
&.lg {
padding: var(--spacing-4) var(--spacing-8);
font-size: var(--font-size-lg);
}
/* Full width */
&.full-width {
width: 100%;
}
}
/* ===========================================
STATUS BADGES (swp-status-badge)
=========================================== */
swp-status-badge {
display: inline-flex;
align-items: center;
gap: var(--spacing-3);
padding: var(--spacing-2) var(--spacing-5);
font-size: var(--font-size-xs);
font-weight: var(--font-weight-medium);
border-radius: var(--radius-pill);
&::before {
content: '';
width: 6px;
height: 6px;
border-radius: var(--radius-full);
background: currentColor;
}
/* Status variants - green */
&.approved,
&.active,
&.valid,
&.confirmed {
background: var(--bg-green-strong);
color: var(--color-green);
}
/* Status variants - amber */
&.draft,
&.invited,
&.expiring,
&.warning,
&.pending {
background: var(--bg-amber-strong);
color: #b45309;
}
/* Use color-amber for pending specifically */
&.pending {
color: var(--color-amber);
}
/* Role variants */
&.owner,
&.enrolled,
&.ferie {
background: var(--bg-teal-strong);
color: var(--color-teal);
}
&.admin {
background: var(--bg-purple-strong);
color: var(--color-purple);
}
&.leader,
&.fri,
&.info,
&.inprogress,
&.in-progress {
background: var(--bg-blue-strong);
color: var(--color-blue);
}
&.employee {
background: var(--color-background-alt);
color: var(--color-text-secondary);
}
/* Danger/red variants */
&.sygdom,
&.danger {
background: var(--bg-red-strong);
color: var(--color-red);
}
/* Completed - muted */
&.completed {
background: var(--color-background-hover);
color: var(--color-text-secondary);
}
}
/* ===========================================
PLAN CARDS (swp-plan-card)
=========================================== */
swp-plan-card {
display: flex;
flex-direction: column;
background: var(--color-surface);
border: 2px solid var(--color-border);
border-radius: var(--radius-xl);
padding: var(--spacing-10);
transition: all var(--transition-normal);
&.selected,
&.current {
border-color: var(--color-teal);
box-shadow: 0 0 0 3px var(--bg-teal-strong);
swp-btn.secondary {
background: var(--color-background-alt);
color: var(--color-text-secondary);
cursor: default;
pointer-events: none;
}
}
&.popular {
border-color: var(--color-amber);
}
&.enterprise {
background: var(--gradient-enterprise);
border-color: var(--color-purple);
}
}
/* Plan badge */
swp-plan-badge {
display: inline-flex;
align-items: center;
gap: var(--spacing-2);
padding: var(--spacing-2) var(--spacing-3);
font-size: var(--font-size-xs);
font-weight: var(--font-weight-semibold);
text-transform: uppercase;
letter-spacing: 0.5px;
border-radius: var(--radius-pill);
width: fit-content;
& i {
font-size: 14px;
}
&.current,
&.selected {
background: var(--bg-teal-strong);
color: var(--color-teal);
}
&.popular {
background: var(--bg-amber-strong);
color: var(--color-amber);
}
&.enterprise {
background: var(--bg-purple-strong);
color: var(--color-purple);
}
&.free {
background: var(--bg-green-strong);
color: var(--color-green);
}
}
/* Plan action */
swp-plan-action {
margin-top: auto;
padding-top: var(--card-padding);
swp-btn {
width: 100%;
}
}
/* ===========================================
AVATARS (swp-avatar)
=========================================== */
swp-avatar {
border-radius: 50%;
background: var(--color-teal);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-weight: var(--font-weight-semibold);
flex-shrink: 0;
/* Default size (md = 40px) */
width: 40px;
height: 40px;
font-size: var(--font-size-sm);
/* Size variants */
&.size-xs {
width: 24px;
height: 24px;
font-size: 10px;
}
&.size-sm {
width: 36px;
height: 36px;
font-size: var(--font-size-xs);
}
&.size-lg {
width: 80px;
height: 80px;
font-size: var(--font-size-2xl);
}
/* Color variants */
&.purple {
background: var(--color-purple);
}
&.blue {
background: var(--color-blue);
}
&.amber {
background: var(--color-amber);
}
&.teal {
background: var(--color-teal);
}
}
/* ===========================================
ICON BUTTONS (swp-icon-btn)
=========================================== */
swp-icon-btn {
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: var(--radius-md);
background: transparent;
border: none;
color: var(--color-text-secondary);
cursor: pointer;
transition: all var(--transition-fast);
& i {
font-size: 18px;
}
&:hover {
background: var(--color-background-alt);
color: var(--color-text);
}
&.danger:hover {
background: var(--bg-red-medium);
color: var(--color-red);
}
}
/* ===========================================
CARDS (swp-card)
=========================================== */
swp-card {
display: block;
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--border-radius-lg);
padding: var(--card-padding);
}
/* Section label - simple card header */
swp-section-label {
display: block;
font-size: var(--font-size-xs);
font-weight: var(--font-weight-semibold);
color: var(--color-text);
text-transform: uppercase;
letter-spacing: 0.5px;
padding-bottom: var(--spacing-4);
border-bottom: 1px solid var(--color-border);
margin-bottom: var(--spacing-6);
}
/* Section header - wrapper when action link is needed */
swp-section-header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: var(--spacing-4);
border-bottom: 1px solid var(--color-border);
margin-bottom: var(--spacing-6);
swp-section-label {
padding-bottom: 0;
border-bottom: none;
margin-bottom: 0;
}
}
swp-section-action {
font-size: var(--font-size-sm);
color: var(--color-teal);
cursor: pointer;
transition: opacity var(--transition-fast);
&:hover {
opacity: 0.8;
}
}
swp-card-content {
display: block;
}
swp-card-footer {
display: flex;
justify-content: space-between;
align-items: center;
padding: var(--spacing-6) var(--card-padding);
background: var(--color-background-alt);
border-top: 1px solid var(--color-border);
margin: var(--spacing-6) calc(-1 * var(--card-padding)) calc(-1 * var(--card-padding));
border-radius: 0 0 var(--border-radius-lg) var(--border-radius-lg);
}
/* ===========================================
ADD BUTTON (dashed border style)
=========================================== */
swp-add-button {
display: flex;
align-items: center;
justify-content: center;
gap: var(--spacing-2);
padding: var(--spacing-5);
margin-top: var(--spacing-5);
border: 2px dashed var(--color-border);
border-radius: var(--radius-md);
color: var(--color-text-secondary);
font-size: var(--font-size-md);
cursor: pointer;
transition: all var(--transition-fast);
&:hover {
border-color: var(--color-teal);
color: var(--color-teal);
background: var(--bg-teal-subtle);
}
}
/* ===========================================
USER INFO PATTERN (shared across auth, waitlist, employees, drawers)
=========================================== */
swp-user-info {
display: flex;
align-items: center;
gap: var(--spacing-4);
}
swp-user-info-card {
display: flex;
align-items: center;
gap: var(--spacing-4);
padding: var(--spacing-4);
background: var(--color-background);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
}
swp-user-details {
display: flex;
flex-direction: column;
gap: var(--spacing-1);
flex: 1;
min-width: 0;
}
swp-user-name {
display: block;
font-size: var(--font-size-base);
font-weight: var(--font-weight-medium);
color: var(--color-text);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
swp-user-email {
display: block;
font-size: var(--font-size-sm);
color: var(--color-text-secondary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* ===========================================
FORM INPUTS (shared base styling)
=========================================== */
swp-form-group {
display: flex;
flex-direction: column;
gap: var(--spacing-2);
}
swp-form-label {
display: block;
font-size: var(--font-size-sm);
font-weight: var(--font-weight-medium);
color: var(--color-text);
}
swp-form-input {
position: relative;
input,
select,
textarea {
width: 100%;
padding: var(--spacing-3) var(--spacing-4);
font-size: var(--font-size-base);
font-family: var(--font-family);
color: var(--color-text);
background: var(--color-background);
border: 1px solid var(--color-border);
border-radius: var(--border-radius);
transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
&::placeholder {
color: var(--color-text-muted);
}
&:focus {
outline: none;
border-color: var(--color-teal);
box-shadow: var(--shadow-focus-ring);
}
}
select {
cursor: pointer;
appearance: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 12px center;
padding-right: 40px;
}
textarea {
resize: vertical;
min-height: 80px;
}
}
/* ===========================================
EMPTY STATE PATTERN
=========================================== */
swp-empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: var(--spacing-10) var(--spacing-6);
text-align: center;
& i {
font-size: 48px;
color: var(--color-border);
margin-bottom: var(--spacing-4);
}
& span {
font-size: var(--font-size-base);
color: var(--color-text-secondary);
}
}