96 lines
1.9 KiB
Vue
96 lines
1.9 KiB
Vue
<template>
|
|
<div class="notifications" aria-live="polite">
|
|
<TransitionGroup name="toast">
|
|
<div
|
|
v-for="n in store.items"
|
|
:key="n.id"
|
|
:class="['toast', `toast--${n.type}`]"
|
|
role="status"
|
|
>
|
|
<Icon
|
|
:name="
|
|
n.type === 'success' ? 'carbon:checkmark-filled' : 'carbon:warning-filled'
|
|
"
|
|
size="1.1rem"
|
|
class="toast__icon"
|
|
/>
|
|
<span class="toast__message">{{ n.message }}</span>
|
|
<IconButton
|
|
icon="carbon:close"
|
|
:label="$t('common.dismiss')"
|
|
variant="ghost"
|
|
size="sm"
|
|
@click="store.dismiss(n.id)"
|
|
/>
|
|
</div>
|
|
</TransitionGroup>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
const store = useNotificationsStore()
|
|
</script>
|
|
|
|
<style scoped>
|
|
.notifications {
|
|
position: fixed;
|
|
top: 5rem;
|
|
right: var(--space-4);
|
|
z-index: 50;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-2);
|
|
max-width: 360px;
|
|
}
|
|
|
|
.toast {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--space-2);
|
|
padding: var(--space-3);
|
|
background: var(--surface-card);
|
|
border: 1px solid var(--border-default);
|
|
/* Colour is doubled by the icon + message, never the sole signal. */
|
|
border-left-width: 3px;
|
|
border-radius: var(--radius-lg);
|
|
box-shadow: var(--shadow-3);
|
|
}
|
|
|
|
.toast--success {
|
|
border-left-color: var(--success);
|
|
}
|
|
.toast--success .toast__icon {
|
|
color: var(--success);
|
|
}
|
|
|
|
.toast--error {
|
|
border-left-color: var(--danger);
|
|
}
|
|
.toast--error .toast__icon {
|
|
color: var(--danger);
|
|
}
|
|
|
|
.toast__icon {
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.toast__message {
|
|
flex: 1;
|
|
min-width: 0;
|
|
font-family: var(--font-body);
|
|
font-size: var(--text-sm);
|
|
color: var(--text-body);
|
|
}
|
|
|
|
.toast-enter-active,
|
|
.toast-leave-active {
|
|
transition:
|
|
opacity 200ms ease,
|
|
transform 200ms ease;
|
|
}
|
|
.toast-enter-from,
|
|
.toast-leave-to {
|
|
opacity: 0;
|
|
transform: translateX(16px);
|
|
}
|
|
</style>
|