feat(ext): shared toast notification system
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
/// to the detail view.
|
||||
|
||||
import { getState, setState, sendMessage, navigate, escapeHtml, openVaultTab } from '../../shared/state';
|
||||
import { showToast } from '../../shared/toast';
|
||||
import {
|
||||
GLYPH_VAULT_TAB,
|
||||
GLYPH_DEVICES, GLYPH_LOCK,
|
||||
@@ -130,11 +131,14 @@ export function renderItemList(app: HTMLElement): void {
|
||||
if (listResp.ok) {
|
||||
const data = listResp.data as { items: Array<[ItemId, ManifestEntry]> };
|
||||
setState({ entries: data.items, loading: false });
|
||||
showToast('Synced', 'success');
|
||||
return;
|
||||
}
|
||||
setState({ loading: false, error: listResp.error });
|
||||
showToast(listResp.error ?? 'Sync failed', 'error');
|
||||
} else {
|
||||
setState({ loading: false, error: resp.error });
|
||||
showToast(resp.error ?? 'Sync failed', 'error');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1660,4 +1660,42 @@ textarea {
|
||||
|
||||
.type-card__icon { font-size: 20px; margin-bottom: 4px; }
|
||||
.type-card__label { font-size: 12px; font-weight: 600; }
|
||||
|
||||
/* Toast notifications */
|
||||
.relicario-toast-container {
|
||||
position: fixed;
|
||||
bottom: 16px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
pointer-events: none;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.vault-shell .relicario-toast-container {
|
||||
left: auto;
|
||||
right: 24px;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.relicario-toast {
|
||||
padding: 8px 16px;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
opacity: 0;
|
||||
transform: translateY(8px);
|
||||
transition: opacity 0.2s, transform 0.2s;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.relicario-toast--visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.relicario-toast--success { background: #1f4a24; color: #aff0b5; border: 1px solid #238636; }
|
||||
.relicario-toast--error { background: #4a1f1f; color: #f0afaf; border: 1px solid #ab2b20; }
|
||||
.relicario-toast--info { background: #1f2d4a; color: #afc8f0; border: 1px solid #1f6feb; }
|
||||
.type-card__desc { font-size: 10px; color: var(--text-muted, #8b949e); margin-top: 2px; }
|
||||
|
||||
26
extension/src/shared/toast.ts
Normal file
26
extension/src/shared/toast.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
export function showToast(
|
||||
message: string,
|
||||
type: 'success' | 'error' | 'info' = 'info',
|
||||
durationMs = 2500,
|
||||
): void {
|
||||
let container = document.querySelector<HTMLElement>('.relicario-toast-container');
|
||||
if (!container) {
|
||||
container = document.createElement('div');
|
||||
container.className = 'relicario-toast-container';
|
||||
document.body.appendChild(container);
|
||||
}
|
||||
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `relicario-toast relicario-toast--${type}`;
|
||||
toast.textContent = message;
|
||||
container.appendChild(toast);
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => toast.classList.add('relicario-toast--visible'));
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
toast.classList.remove('relicario-toast--visible');
|
||||
toast.addEventListener('transitionend', () => toast.remove(), { once: true });
|
||||
}, durationMs);
|
||||
}
|
||||
@@ -1719,3 +1719,41 @@ textarea {
|
||||
background: linear-gradient(to top, rgba(17, 22, 30, 0.7), transparent);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Toast notifications */
|
||||
.relicario-toast-container {
|
||||
position: fixed;
|
||||
bottom: 16px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
pointer-events: none;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.vault-shell .relicario-toast-container {
|
||||
left: auto;
|
||||
right: 24px;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.relicario-toast {
|
||||
padding: 8px 16px;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
opacity: 0;
|
||||
transform: translateY(8px);
|
||||
transition: opacity 0.2s, transform 0.2s;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.relicario-toast--visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.relicario-toast--success { background: #1f4a24; color: #aff0b5; border: 1px solid #238636; }
|
||||
.relicario-toast--error { background: #4a1f1f; color: #f0afaf; border: 1px solid #ab2b20; }
|
||||
.relicario-toast--info { background: #1f2d4a; color: #afc8f0; border: 1px solid #1f6feb; }
|
||||
|
||||
Reference in New Issue
Block a user