diff --git a/UI_UPDATE.MD b/UI_UPDATE.MD index 5bb4c6e..0137412 100644 --- a/UI_UPDATE.MD +++ b/UI_UPDATE.MD @@ -246,31 +246,31 @@ Always come back and update UI_UPDATE.MD once complete with task and task item. - [x] Add hover state animations for interactive icons #### 2.4.4: Accessibility Implementation -- [ ] Add screen reader labels for decorative icons -- [ ] Implement focus indicators for icon buttons -- [ ] Test keyboard navigation for icon controls +- [x] Add screen reader labels for decorative icons +- [x] Implement focus indicators for icon buttons +- [x] Test keyboard navigation for icon controls ### Sub-task 2.5: Component Visual Polish #### 2.5.1: Button Style Redesign -- [ ] Create button component with multiple variants -- [ ] Implement consistent button sizing and padding -- [ ] Add button state variations (hover, active, disabled) +- [x] Create button component with multiple variants +- [x] Implement consistent button sizing and padding +- [x] Add button state variations (hover, active, disabled) #### 2.5.2: Card Design Updates -- [ ] Redesign card components with modern styling -- [ ] Implement consistent card shadows and borders -- [ ] Add card interaction states +- [x] Redesign card components with modern styling +- [x] Implement consistent card shadows and borders +- [x] Add card interaction states #### 2.5.3: Form Element Updates -- [ ] Enhance input field styling -- [ ] Create consistent form element design -- [ ] Implement form validation states +- [x] Enhance input field styling +- [x] Create consistent form element design +- [x] Implement form validation states #### 2.5.4: Loading States -- [ ] Implement skeleton loading patterns -- [ ] Create smooth loading transitions -- [ ] Add stateful component styling +- [x] Implement skeleton loading patterns +- [x] Create smooth loading transitions +- [x] Add stateful component styling --- diff --git a/static/css/components.css b/static/css/components.css index dca71e4..e4d4ab5 100644 --- a/static/css/components.css +++ b/static/css/components.css @@ -1,5 +1,529 @@ /* Component styles - Reusable UI components */ +/* ================================================================= + BUTTON COMPONENT SYSTEM + ================================================================= */ + +/* Base button styles */ +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + gap: var(--spacing-2); + padding: var(--spacing-3) var(--spacing-5); + border: 2px solid transparent; + border-radius: var(--border-radius-lg); + font-family: var(--font-family-base); + font-size: var(--font-size-sm); + font-weight: var(--font-weight-semibold); + text-align: center; + text-decoration: none; + cursor: pointer; + transition: all var(--transition-fast); + user-select: none; + position: relative; + overflow: hidden; + min-height: var(--min-tap-target-size, 44px); + box-sizing: border-box; +} + +/* Button sizes */ +.btn-sm { + padding: var(--spacing-2) var(--spacing-4); + font-size: var(--font-size-xs); + min-height: var(--min-tap-target-size-sm, 36px); +} + +.btn-lg { + padding: var(--spacing-4) var(--spacing-6); + font-size: var(--font-size-base); + min-height: var(--min-tap-target-size-lg, 52px); +} + +/* Button variants */ +.btn-primary { + background: linear-gradient(135deg, var(--color-primary), var(--color-primary-darker)); + color: var(--color-on-primary); + box-shadow: var(--elevation-3); + border-color: var(--color-primary); +} + +.btn-secondary { + background: var(--color-secondary); + color: var(--color-on-secondary); + border-color: var(--color-secondary); +} + +.btn-accent { + background: linear-gradient(135deg, var(--color-accent), var(--color-accent-darker)); + color: var(--color-on-accent); + box-shadow: var(--elevation-3); + border-color: var(--color-accent); +} + +.btn-outline { + background: transparent; + border-color: var(--color-outline); + color: var(--color-on-surface); +} + +.btn-outline-primary { + background: transparent; + border-color: var(--color-primary); + color: var(--color-primary); +} + +.btn-text { + background: transparent; + border-color: transparent; + color: var(--color-primary); + padding: var(--spacing-2) var(--spacing-3); + box-shadow: none; +} + +/* Button states */ +.btn:hover { + /* Transform handled by state variants */ +} + +.btn:active { + transform: translateY(0); +} + +.btn:disabled { + opacity: 0.6; + cursor: not-allowed; + transform: none !important; +} + +.btn-primary:hover { + background: linear-gradient(135deg, var(--color-primary-light), var(--color-primary)); + transform: translateY(-1px); + box-shadow: var(--elevation-4); +} + +.btn-secondary:hover { + transform: translateY(-1px); + box-shadow: var(--elevation-2); +} + +.btn-accent:hover { + background: linear-gradient(135deg, var(--color-accent-light), var(--color-accent)); + transform: translateY(-1px); + box-shadow: var(--elevation-4); +} + +.btn-outline:hover { + background: var(--color-surface-variant); +} + +.btn-outline-primary:hover { + background: var(--color-primary); + color: var(--color-on-primary); +} + +.btn-text:hover { + background: rgba(var(--color-primary-rgb), 0.1); +} + +/* Focus states for accessibility */ +.btn:focus-visible { + outline: 2px solid var(--color-focus); + outline-offset: 2px; +} + +/* Loading state */ +.btn-loading { + position: relative; + color: transparent; +} + +.btn-loading::after { + position: absolute; + content: ''; + width: 1em; + height: 1em; + border: 2px solid rgba(255,255,255,0.3); + border-top: 2px solid white; + border-radius: 50%; + animation: spin 1s linear infinite; +} + +/* Full width button */ +.btn-full { + width: 100%; +} + +/* Icon buttons */ +.btn-icon { + padding: var(--spacing-2); + width: auto; + aspect-ratio: 1; +} + +.btn-icon-only { + width: var(--min-tap-target-size, 44px); + height: var(--min-tap-target-size, 44px); + padding: 0; +} + +/* ================================================================= + CARD COMPONENT SYSTEM + ================================================================= */ + +/* Base card styles */ +.card { + background: var(--color-surface); + border-radius: var(--border-radius-lg); + box-shadow: var(--elevation-1); + border: 1px solid var(--color-outline-variant); + transition: all var(--transition-fast); + overflow: hidden; + position: relative; +} + +.card-elevated { + box-shadow: var(--elevation-2); +} + +.card-outlined { + border-width: 2px; + background: var(--color-surface); +} + +.card-header { + padding: var(--spacing-4); + border-bottom: 1px solid var(--color-outline-variant); + background: var(--color-surface-variant); +} + +.card-body { + padding: var(--spacing-4); +} + +.card-footer { + padding: var(--spacing-4); + border-top: 1px solid var(--color-outline-variant); + background: var(--color-surface-variant); +} + +/* Card interaction states */ +.card:hover { + transform: translateY(-2px); + box-shadow: var(--elevation-3); +} + +.card-interactive { + cursor: pointer; +} + +.card-interactive:hover { + transform: translateY(-2px); + box-shadow: var(--elevation-3); +} + +.card-interactive:active { + transform: translateY(0); + box-shadow: var(--elevation-1); +} + +.card:focus-visible { + outline: 2px solid var(--color-focus); + outline-offset: 2px; +} + +/* Card variants */ +.card-compact .card-body { + padding: var(--spacing-3); +} + +.card-compact .card-header, +.card-compact .card-footer { + padding: var(--spacing-3); +} + +/* ================================================================= + FORM ELEMENT SYSTEM + ================================================================= */ + +/* Base input styles */ +.form-control { + width: 100%; + padding: var(--spacing-3) var(--spacing-4); + border: 2px solid var(--color-outline); + border-radius: var(--border-radius-md); + background: var(--color-surface); + color: var(--color-on-surface); + font-family: inherit; + font-size: var(--font-size-sm); + transition: all var(--transition-fast); + box-sizing: border-box; +} + +.form-control:focus { + outline: none; + border-color: var(--color-primary); + box-shadow: 0 0 0 3px var(--focus-ring); +} + +.form-label { + display: block; + margin-bottom: var(--spacing-2); + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + color: var(--color-on-surface); +} + +.form-input, +.form-textarea, +.form-select { + /* Inherit from form-control */ + width: 100%; + padding: var(--spacing-3) var(--spacing-4); + border: 2px solid var(--color-outline); + border-radius: var(--border-radius-md); + background: var(--color-surface); + color: var(--color-on-surface); + font-family: inherit; + font-size: var(--font-size-sm); + transition: all var(--transition-fast); + box-sizing: border-box; +} + +.form-input:focus, +.form-textarea:focus, +.form-select:focus { + outline: none; + border-color: var(--color-primary); + box-shadow: 0 0 0 3px var(--focus-ring); +} + +/* Form row for horizontal layouts */ +.form-row { + display: flex; + gap: var(--spacing-4); + align-items: flex-start; +} + +.form-row .form-control { + flex: 1; +} + +/* Validation states */ +.form-group { + margin-bottom: var(--spacing-4); + position: relative; +} + +.form-group--error .form-control { + border-color: var(--color-error); +} + +.form-group--error .form-control:focus { + box-shadow: 0 0 0 3px rgba(var(--color-error-rgb), 0.2); +} + +.form-group--success .form-control { + border-color: var(--color-success); +} + +.form-group--success .form-control:focus { + box-shadow: 0 0 0 3px rgba(var(--color-success-rgb), 0.2); +} + +.form-error, +.form-success { + font-size: var(--font-size-xs); + margin-top: var(--spacing-1); + display: block; +} + +.form-error { + color: var(--color-error); +} + +.form-success { + color: var(--color-success); +} + +/* ================================================================= + LOADING STATES - SKELETONS AND TRANSITIONS + ================================================================= */ + +/* Skeleton loading animations */ +@keyframes skeleton-pulse { + 0% { opacity: 1; } + 50% { opacity: 0.6; } + 100% { opacity: 1; } +} + +/* Base skeleton styles */ +.skeleton { + background: linear-gradient(90deg, var(--color-surface-variant) 25%, var(--color-surface) 50%, var(--color-surface-variant) 75%); + background-size: 200% 100%; + animation: skeleton-pulse 1.5s ease-in-out infinite, skeleton-shimmer 1.5s ease-in-out infinite; + border-radius: var(--border-radius-sm); +} + +@keyframes skeleton-shimmer { + 0% { background-position: -200% 0; } + 100% { background-position: 200% 0; } +} + +/* Specific skeleton types */ +.skeleton-text { + height: var(--font-size-base); + width: 100%; + margin-bottom: var(--spacing-2); +} + +.skeleton-text:last-child { + margin-bottom: 0; +} + +.skeleton-avatar { + width: 40px; + height: 40px; + border-radius: 50%; +} + +.skeleton-button { + height: var(--min-tap-target-size, 44px); + width: 120px; + border-radius: var(--border-radius-lg); +} + +.skeleton-card { + padding: var(--spacing-4); + margin-bottom: var(--spacing-4); +} + +.skeleton-card .skeleton-header { + height: var(--font-size-lg); + width: 60%; + margin-bottom: var(--spacing-3); +} + +.skeleton-card .skeleton-content { + height: var(--font-size-sm); + width: 100%; + margin-bottom: var(--spacing-1); +} + +.skeleton-card .skeleton-content:nth-child(2) { + width: 80%; +} + +.skeleton-card .skeleton-content:nth-child(3) { + width: 90%; +} + +/* Loading overlay */ +.loading-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(var(--color-surface-rgb), 0.8); + display: flex; + align-items: center; + justify-content: center; + z-index: 10; + opacity: 0; + transition: opacity var(--transition-fast); + pointer-events: none; +} + +.loading-overlay.active { + opacity: 1; + pointer-events: auto; +} + +/* Loading spinner */ +.loading-spinner { + width: 40px; + height: 40px; + border: 3px solid var(--color-surface-variant); + border-top: 3px solid var(--color-primary); + border-radius: 50%; + animation: spin 1s linear infinite; +} + +/* Loading bar */ +.loading-bar { + width: 100%; + height: 3px; + background: var(--color-surface-variant); + border-radius: 2px; + overflow: hidden; + position: relative; +} + +.loading-bar::after { + content: ''; + position: absolute; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, var(--color-primary), transparent); + animation: loading-bar-anim 1.5s ease-in-out infinite; +} + +@keyframes loading-bar-anim { + 0% { transform: translateX(-100%); } + 100% { transform: translateX(100%); } +} + +/* ================================================================= + STATEFUL COMPONENTS - Interactive States + ================================================================= */ + +/* State utilities for dynamic components */ +.state-loading { + position: relative; + overflow: hidden; +} + +.state-loading::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.1) 50%, transparent 100%); + animation: state-loading-shimmer 2s infinite; + z-index: 1; +} + +@keyframes state-loading-shimmer { + 0% { transform: translateX(-100%); } + 100% { transform: translateX(100%); } +} + +.state-disabled { + opacity: 0.6; + pointer-events: none; +} + +.state-expanded { + transform: rotate(180deg); +} + +.state-collapsed { + transform: rotate(0deg); +} + +.state-active { + background: var(--color-primary); + color: var(--color-on-primary); +} + +.state-inactive { + background: var(--color-surface-variant); + color: var(--color-on-surface); +} + /* ================================================================= VIDEO HEADER - Top section of video area ================================================================= */ diff --git a/static/css/icons.css b/static/css/icons.css index b70daa4..b615084 100644 --- a/static/css/icons.css +++ b/static/css/icons.css @@ -207,6 +207,69 @@ height: var(--current-icon-size); } +/* ================================================================= + ACCESSIBILITY - Screen Reader Support + ================================================================= */ + +/* Screen reader only text - hide visually but available to assistive tech */ +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +/* Screen reader only - but show when focused for keyboard users */ +.sr-only:focus { + position: static; + width: auto; + height: auto; + padding: 0.5rem; + margin: 0; + overflow: visible; + clip: auto; + white-space: normal; + background: var(--color-surface); + color: var(--color-on-surface); + border-radius: var(--border-radius-md); + box-shadow: var(--elevation-3); + z-index: var(--z-tooltip); +} + +/* ================================================================= + FOCUS INDICATORS FOR ICON CONTROLS + ================================================================= */ + +/* Base focus styles for interactive icons */ +.icon-interactive:focus { + outline: 2px solid var(--color-focus); + outline-offset: 2px; + border-radius: var(--border-radius-sm); +} + +/* Enhanced focus ring that matches design system */ +.icon-focus-ring { + position: relative; +} + +.icon-focus-ring:focus::after { + content: ''; + position: absolute; + top: -2px; + left: -2px; + right: -2px; + bottom: -2px; + border: 2px solid var(--color-focus); + border-radius: var(--border-radius-md); + z-index: 1; + pointer-events: none; +} + /* ================================================================= ANIMATED ICONS ================================================================= */