feat: Add complete Docker deployment with web-based setup wizard
Major additions: - Web-based setup wizard (setup.php, setup_wizard.php, setup-wizard.js) - Production Docker configuration (docker-compose.prod.yml, .env.production) - Database initialization SQL files (deploy/init_settings.sql) - Template builder system with drag-and-drop UI - Advanced features (OAuth, CDN, enhanced analytics, monetization) - Comprehensive documentation (deployment guides, quick start, feature docs) - Design system with accessibility and responsive layout - Deployment automation scripts (deploy.ps1, generate-secrets.ps1) Setup wizard allows customization of: - Platform name and branding - Domain configuration - Membership tiers and pricing - Admin credentials - Feature toggles Database includes 270+ tables for complete video streaming platform with advanced features for analytics, moderation, template building, and monetization. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
515
f_scripts/shared/accessibility.css
Normal file
515
f_scripts/shared/accessibility.css
Normal file
@@ -0,0 +1,515 @@
|
||||
/**
|
||||
* EasyStream Accessibility Enhancements
|
||||
* WCAG 2.1 AA Compliance CSS
|
||||
* Version: 1.0
|
||||
*/
|
||||
|
||||
/* ==================== FOCUS INDICATORS ==================== */
|
||||
|
||||
/* Enhanced focus styles for keyboard navigation */
|
||||
*:focus {
|
||||
outline: none; /* Remove default */
|
||||
}
|
||||
|
||||
*:focus-visible {
|
||||
outline: 3px solid var(--focus-ring-color, #06a2cb);
|
||||
outline-offset: 2px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* Specific focus styles for interactive elements */
|
||||
a:focus-visible,
|
||||
button:focus-visible,
|
||||
input:focus-visible,
|
||||
textarea:focus-visible,
|
||||
select:focus-visible,
|
||||
[role="button"]:focus-visible,
|
||||
[role="link"]:focus-visible,
|
||||
[tabindex]:focus-visible {
|
||||
outline: 3px solid var(--focus-ring-color, #06a2cb);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* Video player controls focus */
|
||||
.video-js button:focus-visible,
|
||||
.vjs-control:focus-visible {
|
||||
outline: 3px solid #fff;
|
||||
outline-offset: 2px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
/* ==================== CONTRAST IMPROVEMENTS ==================== */
|
||||
|
||||
/* Ensure minimum 4.5:1 contrast ratio for normal text */
|
||||
body {
|
||||
color: var(--color-text-primary, #111827);
|
||||
background: var(--color-bg-primary, #ffffff);
|
||||
}
|
||||
|
||||
[data-theme*="dark"] body {
|
||||
color: var(--color-text-primary, #f0f0f0);
|
||||
background: var(--color-bg-primary, #121212);
|
||||
}
|
||||
|
||||
/* Link contrast */
|
||||
a {
|
||||
color: var(--secondary-color, #0793e2);
|
||||
text-decoration-skip-ink: auto;
|
||||
}
|
||||
|
||||
a:hover,
|
||||
a:focus {
|
||||
color: var(--primary-color, #06a2cb);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Button contrast */
|
||||
.btn,
|
||||
button {
|
||||
/* Ensure text contrast on buttons */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.btn-primary,
|
||||
.button-blue {
|
||||
background: var(--primary-color, #06a2cb);
|
||||
color: #ffffff;
|
||||
border: 2px solid var(--primary-color, #06a2cb);
|
||||
}
|
||||
|
||||
.btn-primary:hover,
|
||||
.button-blue:hover {
|
||||
background: var(--third-color, #92cefb);
|
||||
border-color: var(--third-color, #92cefb);
|
||||
}
|
||||
|
||||
/* ==================== TEXT SIZING & READABILITY ==================== */
|
||||
|
||||
/* Responsive font sizes */
|
||||
html {
|
||||
font-size: 16px; /* Base size for 1rem */
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
html {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Line height for readability (WCAG SC 1.4.8) */
|
||||
p,
|
||||
li,
|
||||
dd,
|
||||
dt {
|
||||
line-height: 1.5;
|
||||
max-width: 80ch; /* Optimal line length for readability */
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
line-height: 1.3;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
/* Prevent text from being too small */
|
||||
.small-thumbs h2,
|
||||
.small-thumbs h3,
|
||||
.text-sm,
|
||||
small {
|
||||
font-size: max(0.875rem, 14px);
|
||||
}
|
||||
|
||||
/* ==================== TOUCH TARGETS ==================== */
|
||||
|
||||
/* Minimum 44x44px touch targets (WCAG SC 2.5.5) */
|
||||
button,
|
||||
a,
|
||||
input[type="checkbox"],
|
||||
input[type="radio"],
|
||||
select,
|
||||
.btn,
|
||||
.touch-target,
|
||||
[role="button"],
|
||||
[role="link"] {
|
||||
min-height: 44px;
|
||||
min-width: 44px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 8px 16px;
|
||||
}
|
||||
|
||||
/* Exception for text-only links in paragraphs */
|
||||
p a,
|
||||
li a {
|
||||
min-height: auto;
|
||||
min-width: auto;
|
||||
display: inline;
|
||||
padding: 2px 0;
|
||||
}
|
||||
|
||||
/* Icon buttons */
|
||||
.icon-button,
|
||||
button[class*="icon-"],
|
||||
a[class*="icon-"] {
|
||||
min-height: 44px;
|
||||
min-width: 44px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/* ==================== SKIP LINKS ==================== */
|
||||
|
||||
.skip-links {
|
||||
position: absolute;
|
||||
top: -100px;
|
||||
left: 0;
|
||||
z-index: 10000;
|
||||
background: var(--primary-color, #06a2cb);
|
||||
}
|
||||
|
||||
.skip-links a {
|
||||
position: absolute;
|
||||
top: -100px;
|
||||
left: 0;
|
||||
padding: 12px 16px;
|
||||
background: var(--primary-color, #06a2cb);
|
||||
color: #ffffff;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
border-radius: 0 0 4px 0;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.skip-links a:focus {
|
||||
top: 0;
|
||||
outline: 3px solid #ffffff;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* ==================== SCREEN READER ONLY ==================== */
|
||||
|
||||
.sr-only,
|
||||
.visually-hidden {
|
||||
position: absolute !important;
|
||||
width: 1px !important;
|
||||
height: 1px !important;
|
||||
padding: 0 !important;
|
||||
margin: -1px !important;
|
||||
overflow: hidden !important;
|
||||
clip: rect(0, 0, 0, 0) !important;
|
||||
white-space: nowrap !important;
|
||||
border-width: 0 !important;
|
||||
}
|
||||
|
||||
/* Allow screen reader text to be focusable when navigated to via keyboard */
|
||||
.sr-only:focus,
|
||||
.visually-hidden:focus {
|
||||
position: static !important;
|
||||
width: auto !important;
|
||||
height: auto !important;
|
||||
overflow: visible !important;
|
||||
clip: auto !important;
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
/* ==================== FORM LABELS & INPUTS ==================== */
|
||||
|
||||
/* Ensure labels are visible and associated */
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
/* Required field indicator */
|
||||
.required::after,
|
||||
label.required::after {
|
||||
content: " *";
|
||||
color: var(--color-error, #ef4444);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Error states */
|
||||
input:invalid:not(:placeholder-shown),
|
||||
.input-error,
|
||||
.error {
|
||||
border-color: var(--color-error, #ef4444) !important;
|
||||
background: var(--color-error-bg, #fee2e2);
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: var(--color-error-text, #991b1b);
|
||||
font-size: 0.875rem;
|
||||
margin-top: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.error-message::before {
|
||||
content: "⚠";
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Success states */
|
||||
.input-success {
|
||||
border-color: var(--color-success, #10b981) !important;
|
||||
background: var(--color-success-bg, #d1fae5);
|
||||
}
|
||||
|
||||
/* ==================== REDUCED MOTION ==================== */
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
scroll-behavior: auto !important;
|
||||
}
|
||||
|
||||
/* Keep essential animations but make them instant */
|
||||
.spinner,
|
||||
.loading,
|
||||
[class*="animate"] {
|
||||
animation: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================== HIGH CONTRAST MODE ==================== */
|
||||
|
||||
@media (prefers-contrast: high) {
|
||||
* {
|
||||
border-width: 2px !important;
|
||||
}
|
||||
|
||||
button,
|
||||
a,
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
border: 2px solid currentColor !important;
|
||||
}
|
||||
|
||||
:focus-visible {
|
||||
outline-width: 4px !important;
|
||||
outline-offset: 3px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================== DARK MODE PREFERENCES ==================== */
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
/* Respect system preference if no theme is set */
|
||||
body:not([data-theme]) {
|
||||
background: #121212;
|
||||
color: #f0f0f0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================== TABLES ACCESSIBILITY ==================== */
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
font-weight: 600;
|
||||
background: var(--color-bg-tertiary);
|
||||
padding: 12px;
|
||||
border: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 12px;
|
||||
border: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
/* Caption for table context */
|
||||
caption {
|
||||
font-weight: 600;
|
||||
text-align: left;
|
||||
padding: 8px 0;
|
||||
caption-side: top;
|
||||
}
|
||||
|
||||
/* ==================== IMAGES & MEDIA ==================== */
|
||||
|
||||
/* Ensure images don't overflow and have alt text */
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/* Decorative images should have empty alt */
|
||||
img[alt=""],
|
||||
img:not([alt]) {
|
||||
outline: 2px solid orange; /* Dev warning for missing alt */
|
||||
}
|
||||
|
||||
/* Video controls must be accessible */
|
||||
video:focus {
|
||||
outline: 3px solid var(--focus-ring-color, #06a2cb);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* ==================== HEADINGS HIERARCHY ==================== */
|
||||
|
||||
/* Ensure proper heading hierarchy is visually clear */
|
||||
h1 {
|
||||
font-size: clamp(1.5rem, 5vw, 2.25rem);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: clamp(1.25rem, 4vw, 1.875rem);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: clamp(1.125rem, 3vw, 1.5rem);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: clamp(1rem, 2.5vw, 1.25rem);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
h5, h6 {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* ==================== LISTS ==================== */
|
||||
|
||||
/* Ensure lists have proper spacing */
|
||||
ul, ol {
|
||||
padding-left: 1.5em;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
/* ==================== MODALS & OVERLAYS ==================== */
|
||||
|
||||
/* Modal focus trap indicator */
|
||||
[role="dialog"]:focus,
|
||||
.modal:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Modal backdrop */
|
||||
.modal-backdrop,
|
||||
[role="dialog"]::backdrop {
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
|
||||
/* Prevent background scroll when modal is open */
|
||||
body.modal-open {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ==================== LANGUAGE & TEXT DIRECTION ==================== */
|
||||
|
||||
/* Support for RTL languages */
|
||||
[dir="rtl"] {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
[dir="rtl"] .sidebar {
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
/* ==================== STATUS MESSAGES ==================== */
|
||||
|
||||
/* Live regions for dynamic content */
|
||||
[role="status"],
|
||||
[role="alert"],
|
||||
[aria-live] {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.status-message,
|
||||
.alert {
|
||||
padding: 12px 16px;
|
||||
border-radius: 4px;
|
||||
margin: 8px 0;
|
||||
border-left: 4px solid;
|
||||
}
|
||||
|
||||
.status-success {
|
||||
background: var(--color-success-bg);
|
||||
color: var(--color-success-text);
|
||||
border-color: var(--color-success);
|
||||
}
|
||||
|
||||
.status-error {
|
||||
background: var(--color-error-bg);
|
||||
color: var(--color-error-text);
|
||||
border-color: var(--color-error);
|
||||
}
|
||||
|
||||
.status-warning {
|
||||
background: var(--color-warning-bg);
|
||||
color: var(--color-warning-text);
|
||||
border-color: var(--color-warning);
|
||||
}
|
||||
|
||||
.status-info {
|
||||
background: var(--color-info-bg);
|
||||
color: var(--color-info-text);
|
||||
border-color: var(--color-info);
|
||||
}
|
||||
|
||||
/* ==================== PRINT STYLES ==================== */
|
||||
|
||||
@media print {
|
||||
/* Remove unnecessary elements */
|
||||
nav,
|
||||
aside,
|
||||
.no-print,
|
||||
.sidebar,
|
||||
header,
|
||||
footer {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Optimize for print */
|
||||
* {
|
||||
background: white !important;
|
||||
color: black !important;
|
||||
box-shadow: none !important;
|
||||
text-shadow: none !important;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Show URLs for links */
|
||||
a[href]::after {
|
||||
content: " (" attr(href) ")";
|
||||
}
|
||||
|
||||
/* Prevent page breaks inside elements */
|
||||
img,
|
||||
pre,
|
||||
blockquote,
|
||||
table,
|
||||
tr {
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
page-break-after: avoid;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user