@use 'sprucecss/scss/spruce' as *;
.notification-list {
background-color: color('surface');
border: config('border-width-base', $display) solid color('border');
border-radius: radius('lg');
overflow: hidden;
&__header {
align-items: center;
border-block-end: config('border-width-base', $display) solid color('border');
display: flex;
gap: spacer('s');
justify-content: space-between;
padding: spacer('s') spacer('m');
}
&__title {
align-items: center;
display: flex;
font-size: font-size('h5');
gap: spacer('xs');
margin: 0;
}
&__count {
background-color: color('primary');
border-radius: radius('pill');
color: color('primary-foreground', 'btn');
font-family: config('font-family-base', $typography);
font-size: config('font-size-sm', $typography);
padding: 0 spacer('xs');
}
&__items {
@include clear-list;
}
&__item {
align-items: flex-start;
display: flex;
gap: spacer('s');
margin: 0 !important;
padding: spacer('s') spacer('m');
position: relative;
@include a11y-card-link('.notification-list__link');
& + & {
border-block-start: config('border-width-base', $display) solid color('border');
}
&:hover {
background-color: color('surface-muted');
}
&--unread {
background-color: color-alpha('primary', 0.06);
.notification-list__link {
font-weight: 700;
}
.notification-list__time::after {
background-color: color('primary');
block-size: 0.5rem;
border-radius: 50%;
content: '';
display: inline-block;
inline-size: 0.5rem;
margin-inline-start: spacer('xs');
}
}
}
&__icon {
--icon-color: #{color('info', 'alert')};
background-color: color-mix(in srgb, var(--icon-color) 15%, transparent);
block-size: 2.25rem;
border-radius: radius('md');
flex-shrink: 0;
inline-size: 2.25rem;
position: relative;
&::after {
background-color: var(--icon-color);
block-size: 0.75rem;
border-radius: 50%;
content: '';
inline-size: 0.75rem;
inset: 0;
margin: auto;
position: absolute;
}
@each $type in ('success', 'warning', 'danger', 'info') {
&--#{$type} {
--icon-color: #{color($type, 'alert')};
}
}
}
&__content {
flex-grow: 1;
min-inline-size: 0;
}
&__link {
color: color('heading');
font-weight: 600;
text-decoration: none;
&:focus-visible {
outline: none;
&::before {
outline: 2px solid color('focus-ring');
outline-offset: -2px;
}
}
}
&__text {
color: color('muted');
font-size: config('font-size-sm', $typography);
margin: 0;
}
&__time {
align-items: center;
color: color('muted');
display: flex;
flex-shrink: 0;
font-size: config('font-size-sm', $typography);
}
}
<section class="notification-list" aria-labelledby="notifications-title">
<header class="notification-list__header">
<h2 class="notification-list__title" id="notifications-title">Notifications <span class="notification-list__count">2 new</span></h2>
<button class="btn btn--ghost-primary btn--sm" type="button" data-mark-read>Mark all as read</button>
</header>
<ul class="notification-list__items" role="list">
<li class="notification-list__item notification-list__item--unread">
<span class="notification-list__icon notification-list__icon--success" aria-hidden="true"></span>
<div class="notification-list__content">
<a class="notification-list__link" href="#"><span class="sr-only">Unread: </span>Deployment finished</a>
<p class="notification-list__text">spruce-docs was deployed to production.</p>
</div>
<time class="notification-list__time">5m</time>
</li>
<li class="notification-list__item notification-list__item--unread">
<span class="notification-list__icon notification-list__icon--info" aria-hidden="true"></span>
<div class="notification-list__content">
<a class="notification-list__link" href="#"><span class="sr-only">Unread: </span>New comment</a>
<p class="notification-list__text">Maya replied to “Design styles in v3”.</p>
</div>
<time class="notification-list__time">1h</time>
</li>
<li class="notification-list__item">
<span class="notification-list__icon notification-list__icon--warning" aria-hidden="true"></span>
<div class="notification-list__content">
<a class="notification-list__link" href="#">Usage at 80%</a>
<p class="notification-list__text">Your team used 8 of 10 GB storage.</p>
</div>
<time class="notification-list__time">3h</time>
</li>
<li class="notification-list__item">
<span class="notification-list__icon notification-list__icon--danger" aria-hidden="true"></span>
<div class="notification-list__content">
<a class="notification-list__link" href="#">Build failed</a>
<p class="notification-list__text">The preview build of #241 failed.</p>
</div>
<time class="notification-list__time">1d</time>
</li>
</ul>
</section>
(() => {
document.querySelectorAll('.notification-list').forEach((list) => {
list.querySelector('[data-mark-read]')?.addEventListener('click', () => {
list.querySelectorAll('.notification-list__item--unread').forEach((item) => {
item.classList.remove('notification-list__item--unread');
item.querySelector('.sr-only')?.remove();
});
list.querySelector('.notification-list__count')?.remove();
});
});
})();