PlanTempusApp/PlanTempus.Application/wwwroot/css/components.css
Janus C. H. Knudsen 5e2cab9bd5 Refactor CSS using nested selectors and media queries
Improves CSS organization by adopting PostCSS nesting syntax
Enhances responsiveness with refined media query implementations
Reduces code repetition and improves maintainability of stylesheets

Modernizes CSS structure across multiple component stylesheets
2026-01-14 16:31:28 +01:00

694 lines
15 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;
}
/* ===========================================
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);
}
}