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
This commit is contained in:
Janus C. H. Knudsen 2026-01-14 16:31:28 +01:00
parent 29f9c79764
commit 5e2cab9bd5
6 changed files with 1539 additions and 1608 deletions

View file

@ -1,4 +1,4 @@
g/**
/**
* UI Components - Shared reusable components
*
* This file contains all shared UI components used across the application.
@ -21,13 +21,20 @@ g/**
/* ===========================================
BASE PATTERNS - Grid + Subgrid Tables
=========================================== */
/* Base table structure - use with feature-specific column definitions */
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 {
@ -43,23 +50,14 @@ swp-table-row-base {
align-items: center;
border-bottom: 1px solid var(--color-border);
transition: background var(--transition-fast);
}
swp-table-row-base:last-child {
border-bottom: none;
}
&:last-child {
border-bottom: none;
}
swp-table-row-base:hover {
background: var(--color-background-hover);
}
/* Header cells base styling */
swp-table-header-base 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);
&:hover {
background: var(--color-background-hover);
}
}
/* ===========================================
@ -79,10 +77,10 @@ swp-list-item-base {
border-radius: var(--radius-lg);
cursor: pointer;
transition: background var(--transition-fast);
}
swp-list-item-base:hover {
background: var(--color-background-hover);
&:hover {
background: var(--color-background-hover);
}
}
/* ===========================================
@ -118,110 +116,110 @@ swp-btn {
cursor: pointer;
transition: all var(--transition-fast);
text-decoration: none;
& i {
font-size: 18px;
}
}
/* Primary button */
swp-btn.primary {
background: var(--color-teal);
color: white;
border-color: var(--color-teal);
}
/* Primary button */
&.primary {
background: var(--color-teal);
color: white;
border-color: var(--color-teal);
swp-btn.primary:hover {
background: #00796b;
border-color: #00796b;
}
&:hover {
background: #00796b;
border-color: #00796b;
}
swp-btn.primary:active {
transform: translateY(1px);
}
&:active {
transform: translateY(1px);
}
swp-btn.primary:disabled {
background: var(--color-border);
border-color: var(--color-border);
cursor: not-allowed;
}
&:disabled {
background: var(--color-border);
border-color: var(--color-border);
cursor: not-allowed;
}
}
/* Secondary button */
swp-btn.secondary {
background: var(--color-surface);
border: 1px solid var(--color-border);
color: var(--color-text);
}
/* Secondary button */
&.secondary {
background: var(--color-surface);
border: 1px solid var(--color-border);
color: var(--color-text);
swp-btn.secondary:hover {
background: var(--color-background-hover);
}
&:hover {
background: var(--color-background-hover);
}
}
/* Ghost button */
swp-btn.ghost {
background: transparent;
color: var(--color-text-secondary);
}
/* Ghost button */
&.ghost {
background: transparent;
color: var(--color-text-secondary);
swp-btn.ghost:hover {
color: var(--color-text);
}
&:hover {
color: var(--color-text);
}
}
/* Outline button */
swp-btn.outline {
background: transparent;
border: 1px solid var(--color-teal);
color: var(--color-teal);
}
/* Outline button */
&.outline {
background: transparent;
border: 1px solid var(--color-teal);
color: var(--color-teal);
swp-btn.outline:hover {
background: var(--bg-teal-medium);
}
&:hover {
background: var(--bg-teal-medium);
}
swp-btn.outline.purple {
border-color: var(--color-purple);
color: var(--color-purple);
}
&.purple {
border-color: var(--color-purple);
color: var(--color-purple);
swp-btn.outline.purple:hover {
background: var(--bg-purple-medium);
}
&:hover {
background: var(--bg-purple-medium);
}
}
}
/* Social button */
swp-btn.social {
background: var(--color-background);
color: var(--color-text);
border-color: var(--color-border);
}
/* Social button */
&.social {
background: var(--color-background);
color: var(--color-text);
border-color: var(--color-border);
swp-btn.social:hover {
background: var(--color-background-hover);
border-color: var(--color-text-muted);
}
&:hover {
background: var(--color-background-hover);
border-color: var(--color-text-muted);
}
swp-btn.social img {
width: 20px;
height: 20px;
}
& img {
width: 20px;
height: 20px;
}
}
/* Size variants */
swp-btn.sm {
padding: var(--spacing-2) var(--spacing-3);
font-size: var(--font-size-xs);
}
/* Size variants */
&.sm {
padding: var(--spacing-2) var(--spacing-3);
font-size: var(--font-size-xs);
swp-btn.sm i {
font-size: 14px;
}
& i {
font-size: 14px;
}
}
swp-btn.lg {
padding: var(--spacing-4) var(--spacing-8);
font-size: var(--font-size-lg);
}
&.lg {
padding: var(--spacing-4) var(--spacing-8);
font-size: var(--font-size-lg);
}
/* Full width */
swp-btn.full-width {
width: 100%;
/* Full width */
&.full-width {
width: 100%;
}
}
/* ===========================================
@ -235,100 +233,78 @@ swp-status-badge {
font-size: var(--font-size-xs);
font-weight: var(--font-weight-medium);
border-radius: var(--radius-pill);
}
swp-status-badge::before {
content: '';
width: 6px;
height: 6px;
border-radius: var(--radius-full);
background: currentColor;
}
&::before {
content: '';
width: 6px;
height: 6px;
border-radius: var(--radius-full);
background: currentColor;
}
/* Status variants */
swp-status-badge.approved,
swp-status-badge.active {
background: var(--bg-green-strong);
color: var(--color-green);
}
/* Status variants - green */
&.approved,
&.active,
&.valid,
&.confirmed {
background: var(--bg-green-strong);
color: var(--color-green);
}
swp-status-badge.draft,
swp-status-badge.invited {
background: var(--bg-amber-strong);
color: #b45309;
}
/* Status variants - amber */
&.draft,
&.invited,
&.expiring,
&.warning,
&.pending {
background: var(--bg-amber-strong);
color: #b45309;
}
/* Role variants */
swp-status-badge.owner {
background: var(--bg-teal-strong);
color: var(--color-teal);
}
/* Use color-amber for pending specifically */
&.pending {
color: var(--color-amber);
}
swp-status-badge.admin {
background: var(--bg-purple-strong);
color: var(--color-purple);
}
/* Role variants */
&.owner,
&.enrolled,
&.ferie {
background: var(--bg-teal-strong);
color: var(--color-teal);
}
swp-status-badge.leader {
background: var(--bg-blue-strong);
color: var(--color-blue);
}
&.admin {
background: var(--bg-purple-strong);
color: var(--color-purple);
}
swp-status-badge.employee {
background: var(--color-background-alt);
color: var(--color-text-secondary);
}
&.leader,
&.fri,
&.info,
&.inprogress,
&.in-progress {
background: var(--bg-blue-strong);
color: var(--color-blue);
}
/* Additional status variants */
swp-status-badge.valid {
background: var(--bg-green-strong);
color: var(--color-green);
}
&.employee {
background: var(--color-background-alt);
color: var(--color-text-secondary);
}
swp-status-badge.expiring,
swp-status-badge.warning {
background: var(--bg-amber-strong);
color: #b45309;
}
/* Danger/red variants */
&.sygdom,
&.danger {
background: var(--bg-red-strong);
color: var(--color-red);
}
swp-status-badge.enrolled,
swp-status-badge.ferie {
background: var(--bg-teal-strong);
color: var(--color-teal);
}
swp-status-badge.fri,
swp-status-badge.info {
background: var(--bg-blue-strong);
color: var(--color-blue);
}
swp-status-badge.sygdom,
swp-status-badge.danger {
background: var(--bg-red-strong);
color: var(--color-red);
}
/* Booking/scheduling specific variants */
swp-status-badge.confirmed {
background: var(--bg-green-strong);
color: var(--color-green);
}
swp-status-badge.pending {
background: var(--bg-amber-strong);
color: var(--color-amber);
}
swp-status-badge.inprogress,
swp-status-badge.in-progress {
background: var(--bg-blue-strong);
color: var(--color-blue);
}
swp-status-badge.completed {
background: var(--color-background-hover);
color: var(--color-text-secondary);
/* Completed - muted */
&.completed {
background: var(--color-background-hover);
color: var(--color-text-secondary);
}
}
/* ===========================================
@ -342,29 +318,28 @@ swp-plan-card {
border-radius: var(--radius-xl);
padding: var(--spacing-10);
transition: all var(--transition-normal);
}
swp-plan-card.selected,
swp-plan-card.current {
border-color: var(--color-teal);
box-shadow: 0 0 0 3px var(--bg-teal-strong);
}
&.selected,
&.current {
border-color: var(--color-teal);
box-shadow: 0 0 0 3px var(--bg-teal-strong);
swp-plan-card.popular {
border-color: var(--color-amber);
}
swp-btn.secondary {
background: var(--color-background-alt);
color: var(--color-text-secondary);
cursor: default;
pointer-events: none;
}
}
swp-plan-card.enterprise {
background: linear-gradient(135deg, var(--color-surface) 0%, color-mix(in srgb, var(--color-purple) 5%, var(--color-surface)) 100%);
border-color: var(--color-purple);
}
&.popular {
border-color: var(--color-amber);
}
/* Disabled button for current plan */
swp-plan-card.current swp-btn.secondary {
background: var(--color-background-alt);
color: var(--color-text-secondary);
cursor: default;
pointer-events: none;
&.enterprise {
background: var(--gradient-enterprise);
border-color: var(--color-purple);
}
}
/* Plan badge */
@ -379,41 +354,41 @@ swp-plan-badge {
letter-spacing: 0.5px;
border-radius: var(--radius-pill);
width: fit-content;
}
swp-plan-badge.current,
swp-plan-badge.selected {
background: var(--bg-teal-strong);
color: var(--color-teal);
}
& i {
font-size: 14px;
}
swp-plan-badge.popular {
background: var(--bg-amber-strong);
color: var(--color-amber);
}
&.current,
&.selected {
background: var(--bg-teal-strong);
color: var(--color-teal);
}
swp-plan-badge.enterprise {
background: var(--bg-purple-strong);
color: var(--color-purple);
}
&.popular {
background: var(--bg-amber-strong);
color: var(--color-amber);
}
swp-plan-badge.free {
background: var(--bg-green-strong);
color: var(--color-green);
}
&.enterprise {
background: var(--bg-purple-strong);
color: var(--color-purple);
}
swp-plan-badge i {
font-size: 14px;
&.free {
background: var(--bg-green-strong);
color: var(--color-green);
}
}
/* Plan action */
swp-plan-action {
margin-top: auto;
padding-top: var(--card-padding);
}
swp-plan-action swp-btn {
width: 100%;
swp-btn {
width: 100%;
}
}
/* ===========================================
@ -428,49 +403,46 @@ swp-avatar {
justify-content: center;
font-weight: var(--font-weight-semibold);
flex-shrink: 0;
}
/* Default size (md = 40px) */
swp-avatar {
/* Default size (md = 40px) */
width: 40px;
height: 40px;
font-size: var(--font-size-sm);
}
/* Size variants */
swp-avatar.size-xs {
width: 24px;
height: 24px;
font-size: 10px;
}
/* Size variants */
&.size-xs {
width: 24px;
height: 24px;
font-size: 10px;
}
swp-avatar.size-sm {
width: 36px;
height: 36px;
font-size: var(--font-size-xs);
}
&.size-sm {
width: 36px;
height: 36px;
font-size: var(--font-size-xs);
}
swp-avatar.size-lg {
width: 80px;
height: 80px;
font-size: var(--font-size-2xl);
}
&.size-lg {
width: 80px;
height: 80px;
font-size: var(--font-size-2xl);
}
/* Color variants */
swp-avatar.purple {
background: var(--color-purple);
}
/* Color variants */
&.purple {
background: var(--color-purple);
}
swp-avatar.blue {
background: var(--color-blue);
}
&.blue {
background: var(--color-blue);
}
swp-avatar.amber {
background: var(--color-amber);
}
&.amber {
background: var(--color-amber);
}
swp-avatar.teal {
background: var(--color-teal);
&.teal {
background: var(--color-teal);
}
}
/* ===========================================
@ -488,16 +460,16 @@ swp-icon-btn {
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);
@ -536,12 +508,12 @@ swp-section-header {
padding-bottom: var(--spacing-4);
border-bottom: 1px solid var(--color-border);
margin-bottom: var(--spacing-6);
}
swp-section-header swp-section-label {
padding-bottom: 0;
border-bottom: none;
margin-bottom: 0;
swp-section-label {
padding-bottom: 0;
border-bottom: none;
margin-bottom: 0;
}
}
swp-section-action {
@ -549,7 +521,7 @@ swp-section-action {
color: var(--color-teal);
cursor: pointer;
transition: opacity var(--transition-fast);
&:hover {
opacity: 0.8;
}
@ -586,13 +558,14 @@ swp-add-button {
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)
=========================================== */
@ -657,47 +630,44 @@ swp-form-label {
swp-form-input {
position: relative;
}
swp-form-input input,
swp-form-input select,
swp-form-input 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);
}
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);
swp-form-input input::placeholder,
swp-form-input textarea::placeholder {
color: var(--color-text-muted);
}
&::placeholder {
color: var(--color-text-muted);
}
swp-form-input input:focus,
swp-form-input select:focus,
swp-form-input textarea:focus {
outline: none;
border-color: var(--color-teal);
box-shadow: var(--shadow-focus-ring);
}
&:focus {
outline: none;
border-color: var(--color-teal);
box-shadow: var(--shadow-focus-ring);
}
}
swp-form-input 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;
}
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;
}
swp-form-input textarea {
resize: vertical;
min-height: 80px;
textarea {
resize: vertical;
min-height: 80px;
}
}
/* ===========================================
@ -710,13 +680,13 @@ swp-empty-state {
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);