UNPKG

@nestjsvn/swagger-sse

Version:

OpenAPI documentation and interactive Swagger UI for NestJS Server-Sent Events endpoints

503 lines (433 loc) 10.1 kB
/** * Swagger UI SSE Plugin - Main Styles * Enhanced vanilla JavaScript implementation with theme support */ /* CSS Variables for theming */ :root { --sse-primary-color: #007bff; --sse-success-color: #28a745; --sse-danger-color: #dc3545; --sse-warning-color: #ffc107; --sse-info-color: #17a2b8; --sse-light-color: #f8f9fa; --sse-dark-color: #343a40; --sse-border-color: #dee2e6; --sse-text-color: #212529; --sse-bg-color: #ffffff; --sse-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); --sse-border-radius: 0.375rem; --sse-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; --sse-mono-font: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; } /* Dark theme variables */ [data-theme="dark"] { --sse-primary-color: #0d6efd; --sse-success-color: #198754; --sse-danger-color: #dc3545; --sse-warning-color: #fd7e14; --sse-info-color: #0dcaf0; --sse-light-color: #495057; --sse-dark-color: #f8f9fa; --sse-border-color: #495057; --sse-text-color: #f8f9fa; --sse-bg-color: #212529; --sse-shadow: 0 0.125rem 0.25rem rgba(255, 255, 255, 0.075); } /* Main SSE Interface Container */ .sse-interface { margin: 1rem 0; padding: 1rem; border: 1px solid var(--sse-border-color); border-radius: var(--sse-border-radius); background-color: var(--sse-bg-color); color: var(--sse-text-color); font-family: var(--sse-font-family); box-shadow: var(--sse-shadow); transition: all 0.3s ease; } /* Connection Controls */ .sse-controls { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 1rem; padding: 0.75rem; background-color: var(--sse-light-color); border-radius: var(--sse-border-radius); border: 1px solid var(--sse-border-color); } .sse-controls button { padding: 0.5rem 1rem; border: none; border-radius: var(--sse-border-radius); font-size: 0.875rem; font-weight: 500; cursor: pointer; transition: all 0.2s ease; display: inline-flex; align-items: center; gap: 0.5rem; } .sse-connect-btn { background-color: var(--sse-success-color); color: white; } .sse-connect-btn:hover:not(:disabled) { background-color: #218838; transform: translateY(-1px); } .sse-disconnect-btn { background-color: var(--sse-danger-color); color: white; } .sse-disconnect-btn:hover:not(:disabled) { background-color: #c82333; transform: translateY(-1px); } .sse-controls button:disabled { background-color: #6c757d; cursor: not-allowed; opacity: 0.6; transform: none; } /* Connection Status Indicator */ .sse-status { display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.5rem 0.75rem; border-radius: 1rem; font-size: 0.75rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; position: relative; } .sse-status::before { content: ''; width: 8px; height: 8px; border-radius: 50%; display: inline-block; } .sse-status.connected { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; } .sse-status.connected::before { background-color: #28a745; animation: pulse 2s infinite; } .sse-status.connecting { background-color: #fff3cd; color: #856404; border: 1px solid #ffeaa7; } .sse-status.connecting::before { background-color: #ffc107; animation: blink 1s infinite; } .sse-status.disconnected { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; } .sse-status.disconnected::before { background-color: #dc3545; } .sse-status.error { background-color: #f5c6cb; color: #721c24; border: 1px solid #f1b0b7; } .sse-status.error::before { background-color: #dc3545; animation: shake 0.5s infinite; } /* Connection Statistics */ .sse-stats { display: flex; gap: 1rem; margin-left: auto; font-size: 0.75rem; color: var(--sse-text-color); opacity: 0.7; } .sse-stat { display: flex; flex-direction: column; align-items: center; gap: 0.25rem; } .sse-stat-label { font-weight: 500; text-transform: uppercase; letter-spacing: 0.05em; } .sse-stat-value { font-weight: 600; color: var(--sse-primary-color); } /* Event Filters */ .sse-filters { display: flex; gap: 0.75rem; margin-bottom: 1rem; padding: 0.75rem; background-color: var(--sse-light-color); border-radius: var(--sse-border-radius); border: 1px solid var(--sse-border-color); flex-wrap: wrap; } .sse-filter-group { display: flex; flex-direction: column; gap: 0.25rem; min-width: 150px; } .sse-filter-label { font-size: 0.75rem; font-weight: 500; color: var(--sse-text-color); text-transform: uppercase; letter-spacing: 0.05em; } .sse-filter-input, .sse-filter-select { padding: 0.5rem; border: 1px solid var(--sse-border-color); border-radius: var(--sse-border-radius); background-color: var(--sse-bg-color); color: var(--sse-text-color); font-size: 0.875rem; transition: border-color 0.2s ease; } .sse-filter-input:focus, .sse-filter-select:focus { outline: none; border-color: var(--sse-primary-color); box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); } .sse-clear-filters-btn { padding: 0.5rem 0.75rem; background-color: var(--sse-warning-color); color: white; border: none; border-radius: var(--sse-border-radius); font-size: 0.75rem; cursor: pointer; align-self: flex-end; transition: background-color 0.2s ease; } .sse-clear-filters-btn:hover { background-color: #e0a800; } /* Event Log Container */ .sse-event-log { border: 1px solid var(--sse-border-color); border-radius: var(--sse-border-radius); background-color: var(--sse-bg-color); overflow: hidden; } .sse-event-log-header { display: flex; justify-content: space-between; align-items: center; padding: 0.75rem 1rem; background-color: var(--sse-light-color); border-bottom: 1px solid var(--sse-border-color); } .sse-event-log-title { margin: 0; font-size: 1rem; font-weight: 600; color: var(--sse-text-color); } .sse-event-log-controls { display: flex; gap: 0.5rem; } .sse-log-control-btn { padding: 0.25rem 0.5rem; border: 1px solid var(--sse-border-color); border-radius: var(--sse-border-radius); background-color: var(--sse-bg-color); color: var(--sse-text-color); font-size: 0.75rem; cursor: pointer; transition: all 0.2s ease; } .sse-log-control-btn:hover { background-color: var(--sse-light-color); } .sse-auto-scroll-toggle.active { background-color: var(--sse-primary-color); color: white; border-color: var(--sse-primary-color); } /* Virtual Scrolling Container */ .sse-events-container { height: 400px; overflow-y: auto; position: relative; } .sse-events-viewport { position: relative; } .sse-events-spacer { height: 0; } /* Event Items */ .sse-event-item { padding: 0.75rem; border-bottom: 1px solid var(--sse-border-color); font-family: var(--sse-mono-font); font-size: 0.8125rem; transition: background-color 0.2s ease; cursor: pointer; } .sse-event-item:hover { background-color: var(--sse-light-color); } .sse-event-item:last-child { border-bottom: none; } .sse-event-item.expanded { background-color: var(--sse-light-color); } .sse-event-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem; } .sse-event-type { font-weight: 600; color: var(--sse-primary-color); padding: 0.25rem 0.5rem; background-color: rgba(0, 123, 255, 0.1); border-radius: var(--sse-border-radius); font-size: 0.75rem; } .sse-event-timestamp { color: var(--sse-text-color); opacity: 0.7; font-size: 0.75rem; } .sse-event-data { background-color: var(--sse-light-color); padding: 0.75rem; border-radius: var(--sse-border-radius); white-space: pre-wrap; word-break: break-word; max-height: 100px; overflow: hidden; transition: max-height 0.3s ease; } .sse-event-item.expanded .sse-event-data { max-height: none; } .sse-event-expand-btn { background: none; border: none; color: var(--sse-primary-color); cursor: pointer; font-size: 0.75rem; padding: 0.25rem; margin-top: 0.5rem; } /* Loading States */ .sse-loading { display: flex; align-items: center; justify-content: center; padding: 2rem; color: var(--sse-text-color); opacity: 0.7; } .sse-spinner { width: 20px; height: 20px; border: 2px solid var(--sse-border-color); border-top: 2px solid var(--sse-primary-color); border-radius: 50%; animation: spin 1s linear infinite; margin-right: 0.5rem; } /* Animations */ @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } @keyframes blink { 0%, 50% { opacity: 1; } 51%, 100% { opacity: 0.3; } } @keyframes shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-2px); } 75% { transform: translateX(2px); } } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } /* Responsive Design */ @media (max-width: 768px) { .sse-interface { margin: 0.5rem 0; padding: 0.75rem; } .sse-controls { flex-direction: column; gap: 0.5rem; } .sse-controls button { width: 100%; justify-content: center; } .sse-filters { flex-direction: column; } .sse-filter-group { min-width: auto; } .sse-event-log-header { flex-direction: column; gap: 0.5rem; align-items: flex-start; } .sse-events-container { height: 300px; } .sse-event-header { flex-direction: column; align-items: flex-start; gap: 0.25rem; } .sse-stats { flex-direction: column; gap: 0.5rem; } } /* High contrast mode support */ @media (prefers-contrast: high) { .sse-interface { border-width: 2px; } .sse-controls button { border: 2px solid currentColor; } .sse-status { border-width: 2px; } } /* Reduced motion support */ @media (prefers-reduced-motion: reduce) { * { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; } }