quantumkv's picture
Turn the whole design into dark mode only
f253bd2 verified
class StatusBar extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.currentTimeout = null;
}
connectedCallback() {
this.render();
}
render() {
this.shadowRoot.innerHTML = `
<style>
:host {
position: fixed;
top: 0;
left: 50%;
transform: translateX(-50%);
z-index: 1000;
pointer-events: none;
}
.status-bar {
min-width: 300px;
max-width: 600px;
padding: 0.75rem 1.5rem;
margin-top: 1rem;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
font-size: 0.875rem;
font-weight: 500;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
backdrop-filter: blur(10px);
opacity: 0;
transform: translateY(-20px);
transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
pointer-events: auto;
}
.status-bar.visible {
opacity: 1;
transform: translateY(0);
}
.status-bar.success {
background: linear-gradient(135deg, #059669, #047857);
color: white;
}
.status-bar.error {
background: linear-gradient(135deg, #dc2626, #b91c1c);
color: white;
}
.status-bar.loading {
background: linear-gradient(135deg, #2563eb, #1d4ed8);
color: white;
}
.status-message {
flex: 1;
display: flex;
align-items: center;
gap: 0.5rem;
}
.status-icon {
flex-shrink: 0;
}
.status-action {
background: rgba(255, 255, 255, 0.15);
border: 1px solid rgba(255, 255, 255, 0.25);
color: white;
padding: 0.25rem 0.75rem;
border-radius: 4px;
font-size: 0.75rem;
cursor: pointer;
transition: all 0.2s;
}
.status-action:hover {
background: rgba(255, 255, 255, 0.25);
border-color: rgba(255, 255, 255, 0.35);
}
.loading-spinner {
width: 16px;
height: 16px;
border: 2px solid rgba(255, 255, 255, 0.3);
border-top-color: white;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
@media (max-width: 640px) {
:host {
left: 1rem;
right: 1rem;
transform: none;
}
.status-bar {
min-width: auto;
max-width: none;
}
}
</style>
<div id="statusBar" class="status-bar">
<div class="status-message">
<span class="status-icon"></span>
<span class="status-text"></span>
</div>
<button class="status-action hidden" id="statusAction"></button>
</div>
`;
}
show(type, message, duration = 3000, actionText = null, actionCallback = null) {
const statusBar = this.shadowRoot.getElementById('statusBar');
const statusText = this.shadowRoot.querySelector('.status-text');
const statusIcon = this.shadowRoot.querySelector('.status-icon');
const statusAction = this.shadowRoot.getElementById('statusAction');
// Clear any existing timeout
if (this.currentTimeout) {
clearTimeout(this.currentTimeout);
}
// Reset classes
statusBar.className = 'status-bar';
// Set type-specific content
switch (type) {
case 'success':
statusBar.classList.add('success');
statusIcon.innerHTML = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"></polyline></svg>';
break;
case 'error':
statusBar.classList.add('error');
statusIcon.innerHTML = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><line x1="15" y1="9" x2="9" y2="15"></line><line x1="9" y1="9" x2="15" y2="15"></line></svg>';
break;
case 'loading':
statusBar.classList.add('loading');
statusIcon.innerHTML = '<div class="loading-spinner"></div>';
break;
}
// Set message
statusText.textContent = message;
// Handle action button
if (actionText && actionCallback) {
statusAction.textContent = actionText;
statusAction.classList.remove('hidden');
statusAction.onclick = actionCallback;
} else {
statusAction.classList.add('hidden');
statusAction.onclick = null;
}
// Show status bar
setTimeout(() => {
statusBar.classList.add('visible');
}, 10);
// Auto-hide after duration (except for loading)
if (type !== 'loading' && duration > 0) {
this.currentTimeout = setTimeout(() => {
this.hide();
}, duration);
}
}
hide() {
const statusBar = this.shadowRoot.getElementById('statusBar');
statusBar.classList.remove('visible');
// Clear timeout
if (this.currentTimeout) {
clearTimeout(this.currentTimeout);
this.currentTimeout = null;
}
}
// Method to show success message
success(message, duration = 3000) {
this.show('success', message, duration);
}
// Method to show error message with retry
error(message, retryCallback = null) {
this.show('error', message, 5000, 'Retry', retryCallback);
}
// Method to show loading
loading(message = 'Connecting...') {
this.show('loading', message, 0);
}
}
customElements.define('status-bar', StatusBar);