mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Merge pull request #1371 from PR0M3TH3AN/codex/add-notificationcenter-component-with-filters
Add DM NotificationCenter with filters, grouping, and NotificationItem
This commit is contained in:
3 files changed
+317
-24
No files matched your search
@@ -11,4 +11,4 @@
|
||||
--player-modal-primary-inline-padding-lg,clamp(var(--space-sm),2.75vw,var(--space-lg))
|
||||
)}}.revert-modal__layout{display:grid;gap:1.5rem}@media (min-width:1024px){.revert-modal__layout{grid-template-columns:minmax(var(--revert-modal-sidebar-min),var(--revert-modal-sidebar-width)) minmax(0,1fr)}}#playerModal.video-modal__primary{display:block}.video-modal__primary{display:flex;flex-direction:column;gap:1.5rem;min-width:0;min-height:0}#playerModal.video-modal__secondary{display:block}.video-modal__secondary{display:flex;flex-direction:column;gap:1rem;min-width:0;min-height:0;width:100%;align-self:stretch}.video-modal__similar{display:none}@media (min-width:1024px){#playerModal.video-modal__similar{display:block}.video-modal__similar{display:flex;flex-direction:column;gap:1.5rem;align-self:stretch;flex:1 1 auto;min-height:0}#playerModal .video-modal__similar .player-modal__module{height:100%;display:flex;flex:1 1 auto;min-height:0;flex-direction:column}#playerModal .video-modal__similar .player-modal__module-list{flex:1 1 auto;min-height:0}#playerModal .video-modal__similar .player-modal__module-scroll{height:100%;max-height:none;min-height:0}}#playerModal .player-modal__module-item{width:100%}#playerModal#playerModal .player-modal__module-item>.card:not(.player-modal__similar-card){display:block}#playerModal .player-modal__module-item>.card:not(.player-modal__similar-card){display:flex;width:100%;flex-direction:row;flex-wrap:nowrap;align-items:stretch;gap:var(--space-md)}#playerModal#playerModal .player-modal__module-item>.\!card:not(.player-modal__similar-card){display:block}#playerModal .player-modal__module-item>.\!card:not(.player-modal__similar-card){display:flex;width:100%;flex-direction:row;flex-wrap:nowrap;align-items:stretch;gap:var(--space-md)}#playerModal .player-modal__module-item>.card:not(.player-modal__similar-card) .video-card__media{width:clamp(var(--video-modal-item-media-min),18vw,var(--video-modal-item-media-max))}#playerModal .player-modal__module-item>.\!card:not(.player-modal__similar-card) .video-card__media{width:clamp(var(--video-modal-item-media-min),18vw,var(--video-modal-item-media-max))!important}#playerModal .player-modal__module-item>.\!card:not(.player-modal__similar-card) .video-card__media,#playerModal .player-modal__module-item>.card:not(.player-modal__similar-card) .video-card__media{flex-shrink:0;overflow:hidden;border-radius:var(--radius-lg)}#playerModal .player-modal__module-item>.card:not(.player-modal__similar-card) .video-card__content{padding:clamp(var(--space-sm),1.25vw,var(--space-md))}#playerModal .player-modal__module-item>.\!card:not(.player-modal__similar-card) .video-card__content{padding:clamp(var(--space-sm),1.25vw,var(--space-md))!important}#playerModal#playerModal .player-modal__module-item>.card:not(.player-modal__similar-card) .video-card__content{display:block}#playerModal .player-modal__module-item>.card:not(.player-modal__similar-card) .video-card__content{display:flex;min-width:0;flex:1 1 0%;flex-direction:column;gap:var(--space-sm)}#playerModal#playerModal .player-modal__module-item>.\!card:not(.player-modal__similar-card) .video-card__content{display:block}#playerModal .player-modal__module-item>.\!card:not(.player-modal__similar-card) .video-card__content{display:flex;min-width:0;flex:1 1 0%;flex-direction:column;gap:var(--space-sm)}#playerModal#playerModal .player-modal__module-item>.card:not(.player-modal__similar-card) .video-card__meta{display:block}#playerModal .player-modal__module-item>.card:not(.player-modal__similar-card) .video-card__meta{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;font-size:var(--font-size-xs);line-height:var(--line-height-tight);color:var(--text-muted-strong)}#playerModal#playerModal .player-modal__module-item>.\!card:not(.player-modal__similar-card) .video-card__meta{display:block}#playerModal .player-modal__module-item>.\!card:not(.player-modal__similar-card) .video-card__meta{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;font-size:var(--font-size-xs);line-height:var(--line-height-tight);color:var(--text-muted-strong)}#playerModal .video-modal__similar .player-modal__module-list{gap:clamp(var(--space-2xs),.85vw,var(--space-sm))}.player-modal__similar-card{outline:2px solid transparent;outline-offset:2px}.player-modal__similar-card:focus-visible{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);--tw-ring-opacity:0.7;--tw-ring-offset-width:2px;--tw-ring-offset-color:var(--surface-base);transition-property:box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;transition-duration:var(--motion-duration-fast);transition-timing-function:cubic-bezier(0,0,.2,1);--tw-ring-color:var(--color-accent)}#playerModal.player-modal__similar-card{display:block}.player-modal__similar-card{position:relative;displayLine truncated
|
||||
--motion-video-card-backdrop-translate
|
||||
);--video-card-backdrop-scale:1.12;--video-card-backdrop-blur:var(--blur-video-card-backdrop-strong);--tw-shadow:var(--shadow-lg);--tw-shadow-colored:var(--shadow-lg);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.watch-history-card:focus-visible{border-color:var(--color-accent);--tw-border-opacity:0.4;--tw-shadow:var(--shadow-lg);--tw-shadow-colored:var(--shadow-lg);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.watch-history-card[data-state=critical]{border-width:1px;border-color:var(--color-critical);--tw-border-opacity:0.4;background-color:var(--surface-raised-critical)}.watch-history-card[data-state=private]{background-color:var(--surface-raised-private);--tw-shadow:var(--shadow-lg);--tw-shadow-colored:var(--shadow-lg)}.watch-history-card[data-state=disabled],.watch-history-card[data-state=private]{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.watch-history-card[data-state=disabled]{opacity:.6;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000}.watch-history-card[data-alert=nsfw-owner]{border-width:1px;border-color:var(--color-critical);--tw-border-opacity:0.4;background-color:var(--color-black)}.watch-history-card[data-alert=nsfw-owner]:hover{--tw-border-opacity:0.6;--tw-shadow:var(--shadow-lg);--tw-shadow-colored:var(--shadow-lg);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.watch-history-card img[data-thumbnail-state=blurred],.watch-history-card img[data-visual-state=blurred]{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-duration:.15s;transition-duration:var(--motion-duration-base);transition-timing-function:cubic-bezier(.4,0,.2,1);filter:blur(var(--blur-thumbnail-blur));transform:scale(1.05)}.watch-history-card[data-owner-is-viewer=true][data-url-health-state=offline][data-stream-health-state=unhealthy]{border-width:1px;border-color:var(--color-critical);--tw-border-opacity:0.4;background-color:var(--surface-raised-critical)}#playerModal#playerModal .player-modal__module-item>.watch-history-card:not(.player-modal__similar-card){display:block}#playerModal .player-modal__module-item>.watch-history-card:not(.player-modal__similar-card){display:flex;width:100%;flex-direction:row;flex-wrap:nowrap;align-items:stretch;gap:var(--space-md)}#playerModal .player-modal__module-item>.watch-history-card:not(.player-modal__similar-card) .video-card__media{width:clamp(var(--video-modal-item-media-min),18vw,var(--video-modal-item-media-max));flex-shrink:0;overflow:hidden;border-radius:var(--radius-lg)}#playerModal .player-modal__module-item>.watch-history-card:not(.player-modal__similar-card) .video-card__content{padding:clamp(var(--space-sm),1.25vw,var(--space-md))}#playerModal#playerModal .player-modal__module-item>.watch-history-card:not(.player-modal__similar-card) .video-card__content{display:block}#playerModal .player-modal__module-item>.watch-history-card:not(.player-modal__similar-card) .video-card__content{display:flex;min-width:0;flex:1 1 0%;flex-direction:column;gap:var(--space-sm)}#playerModal#playerModal .player-modal__module-item>.watch-history-card:not(.player-modal__similar-card) .video-card__meta{display:block}#playerModal .player-modal__module-item>.watch-history-card:not(.player-modal__similar-card) .video-card__meta{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;font-size:var(--font-size-xs);line-height:var(--line-height-tight);color:var(--text-muted-strong)}.watch-history-card[data-motion=enter]{opacity:0;animation:card-motion-enter .22s ease-out forwards}#playerModal.watch-history-card{display:block}.watch-history-card{display:flex;flex-wrap:wrap;align-items:stretch;gap:1.25rem;padding:1rem;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;transition-duration:var(--motion-duration-base);transition-timing-function:cubic-bezier(0,0,.2,1)}@media (prefers-reduced-motion:reduce){.watch-history-card,.watch-history-card[data-motion=enter]{transition-property:none}.watch-history-card[data-motion=enter]{opacity:1;animation:none}}.watch-history-card:hover{--tw-translate-y:-0.125rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));--tw-shadow:var(--shadow-lg);--tw-shadow-colored:var(--shadow-lg);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}@media (min-width:640px){.watch-history-card{gap:1.5rem;padding:1.25rem}}.watch-history-card--private{border-color:var(--color-info);--tw-border-opacity:0.6}#playerModal.watch-histoLine truncated
|
||||
);--video-card-backdrop-scale:1.12;--video-card-backdrop-blur:var(--blur-video-card-backdrop-strong);--tw-shadow:var(--shadow-lg);--tw-shadow-colored:var(--shadow-lg);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.watch-history-card:focus-visible{border-color:var(--color-accent);--tw-border-opacity:0.4;--tw-shadow:var(--shadow-lg);--tw-shadow-colored:var(--shadow-lg);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.watch-history-card[data-state=critical]{border-width:1px;border-color:var(--color-critical);--tw-border-opacity:0.4;background-color:var(--surface-raised-critical)}.watch-history-card[data-state=private]{background-color:var(--surface-raised-private);--tw-shadow:var(--shadow-lg);--tw-shadow-colored:var(--shadow-lg)}.watch-history-card[data-state=disabled],.watch-history-card[data-state=private]{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.watch-history-card[data-state=disabled]{opacity:.6;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000}.watch-history-card[data-alert=nsfw-owner]{border-width:1px;border-color:var(--color-critical);--tw-border-opacity:0.4;background-color:var(--color-black)}.watch-history-card[data-alert=nsfw-owner]:hover{--tw-border-opacity:0.6;--tw-shadow:var(--shadow-lg);--tw-shadow-colored:var(--shadow-lg);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.watch-history-card img[data-thumbnail-state=blurred],.watch-history-card img[data-visual-state=blurred]{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-duration:.15s;transition-duration:var(--motion-duration-base);transition-timing-function:cubic-bezier(.4,0,.2,1);filter:blur(var(--blur-thumbnail-blur));transform:scale(1.05)}.watch-history-card[data-owner-is-viewer=true][data-url-health-state=offline][data-stream-health-state=unhealthy]{border-width:1px;border-color:var(--color-critical);--tw-border-opacity:0.4;background-color:var(--surface-raised-critical)}#playerModal#playerModal .player-modal__module-item>.watch-history-card:not(.player-modal__similar-card){display:block}#playerModal .player-modal__module-item>.watch-history-card:not(.player-modal__similar-card){display:flex;width:100%;flex-direction:row;flex-wrap:nowrap;align-items:stretch;gap:var(--space-md)}#playerModal .player-modal__module-item>.watch-history-card:not(.player-modal__similar-card) .video-card__media{width:clamp(var(--video-modal-item-media-min),18vw,var(--video-modal-item-media-max));flex-shrink:0;overflow:hidden;border-radius:var(--radius-lg)}#playerModal .player-modal__module-item>.watch-history-card:not(.player-modal__similar-card) .video-card__content{padding:clamp(var(--space-sm),1.25vw,var(--space-md))}#playerModal#playerModal .player-modal__module-item>.watch-history-card:not(.player-modal__similar-card) .video-card__content{display:block}#playerModal .player-modal__module-item>.watch-history-card:not(.player-modal__similar-card) .video-card__content{display:flex;min-width:0;flex:1 1 0%;flex-direction:column;gap:var(--space-sm)}#playerModal#playerModal .player-modal__module-item>.watch-history-card:not(.player-modal__similar-card) .video-card__meta{display:block}#playerModal .player-modal__module-item>.watch-history-card:not(.player-modal__similar-card) .video-card__meta{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;font-size:var(--font-size-xs);line-height:var(--line-height-tight);color:var(--text-muted-strong)}.watch-history-card[data-motion=enter]{opacity:0;animation:card-motion-enter .22s ease-out forwards}#playerModal.watch-history-card{display:block}.watch-history-card{display:flex;flex-wrap:wrap;align-items:stretch;gap:1.25rem;padding:1rem;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;transition-duration:var(--motion-duration-base);transition-timing-function:cubic-bezier(0,0,.2,1)}@media (prefers-reduced-motion:reduce){.watch-history-card,.watch-history-card[data-motion=enter]{transition-property:none}.watch-history-card[data-motion=enter]{opacity:1;animation:none}}.watch-history-card:hover{--tw-translate-y:-0.125rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));--tw-shadow:var(--shadow-lg);--tw-shadow-colored:var(--shadow-lg);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}@media (min-width:640px){.watch-history-card{gap:1.5rem;padding:1.25rem}}.watch-history-card--private{border-color:var(--color-info);--tw-border-opacity:0.6}#playerModal.watch-histoLine truncated
|
||||
+120
-6
@@ -5271,6 +5271,66 @@
|
||||
}
|
||||
|
||||
.dm-notification-center {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-sm);
|
||||
}
|
||||
|
||||
.dm-notification-center__filters {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: var(--space-xs);
|
||||
}
|
||||
|
||||
.dm-notification-center__filter-button {
|
||||
border-radius: var(--radius-full);
|
||||
border: var(--border-width-hairline) solid var(--border-subtle);
|
||||
background: var(--surface-sunken);
|
||||
padding: var(--space-2xs) var(--space-sm);
|
||||
font-size: var(--font-size-2xs);
|
||||
font-weight: 600;
|
||||
color: var(--text-muted);
|
||||
transition: color var(--motion-duration-fast) var(--motion-ease-out),
|
||||
background var(--motion-duration-fast) var(--motion-ease-out),
|
||||
border-color var(--motion-duration-fast) var(--motion-ease-out);
|
||||
}
|
||||
|
||||
.dm-notification-center__filter-button:hover,
|
||||
.dm-notification-center__filter-button:focus-visible {
|
||||
outline: none;
|
||||
border-color: var(--border-strong);
|
||||
background: var(--surface-raised);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.dm-notification-center__filter-button--active {
|
||||
border-color: var(--border-strong);
|
||||
background: var(--surface-overlay-panel);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.dm-notification-center__groups {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-md);
|
||||
}
|
||||
|
||||
.dm-notification-center__group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-xs);
|
||||
}
|
||||
|
||||
.dm-notification-center__group-title {
|
||||
font-size: var(--font-size-2xs);
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: var(--tracking-wide);
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.dm-notification-center__list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-xs);
|
||||
@@ -5281,33 +5341,87 @@
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.dm-notification-center__item {
|
||||
padding: var(--space-xs) var(--space-sm);
|
||||
.dm-notification-item {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
align-items: center;
|
||||
gap: var(--space-sm);
|
||||
padding: var(--space-sm);
|
||||
border-radius: var(--radius-md);
|
||||
border: var(--border-width-hairline) solid var(--border-subtle);
|
||||
background: var(--surface-sunken);
|
||||
font-size: var(--font-size-xs);
|
||||
text-align: left;
|
||||
transition: border-color var(--motion-duration-fast) var(--motion-ease-out),
|
||||
background var(--motion-duration-fast) var(--motion-ease-out);
|
||||
}
|
||||
|
||||
.dm-notification-center__item--info {
|
||||
.dm-notification-item:hover,
|
||||
.dm-notification-item:focus-visible {
|
||||
outline: none;
|
||||
border-color: var(--border-strong);
|
||||
background: var(--surface-raised);
|
||||
}
|
||||
|
||||
.dm-notification-item__icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: var(--icon-size-md);
|
||||
height: var(--icon-size-md);
|
||||
border-radius: var(--radius-full);
|
||||
background: var(--surface-overlay-panel-soft);
|
||||
color: var(--text-muted);
|
||||
font-size: var(--font-size-xs);
|
||||
}
|
||||
|
||||
.dm-notification-item__body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-2xs);
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.dm-notification-item__title {
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.dm-notification-item__message {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.dm-notification-item__meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2xs);
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.dm-notification-item__timestamp {
|
||||
font-variant-numeric: tabular-nums;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.dm-notification-item--info {
|
||||
background: var(--status-info-surface);
|
||||
border-color: var(--status-info-border);
|
||||
color: var(--status-info-on);
|
||||
}
|
||||
|
||||
.dm-notification-center__item--success {
|
||||
.dm-notification-item--success {
|
||||
background: var(--status-success-surface);
|
||||
border-color: var(--status-success-border);
|
||||
color: var(--status-success-on);
|
||||
}
|
||||
|
||||
.dm-notification-center__item--warning {
|
||||
.dm-notification-item--warning {
|
||||
background: var(--status-warning-surface);
|
||||
border-color: var(--status-warning-border);
|
||||
color: var(--status-warning-on);
|
||||
}
|
||||
|
||||
.dm-notification-center__item--error {
|
||||
.dm-notification-item--error {
|
||||
background: var(--status-danger-surface);
|
||||
border-color: var(--status-danger-border);
|
||||
color: var(--status-danger-on);
|
||||
|
||||
+196
-17
@@ -9,32 +9,211 @@ function createElement(doc, tag, className, text) {
|
||||
return element;
|
||||
}
|
||||
|
||||
export function NotificationCenter({ document: doc, notices = [] } = {}) {
|
||||
const FILTERS = [
|
||||
{ id: "all", label: "All" },
|
||||
{ id: "dms", label: "DMs" },
|
||||
{ id: "mentions", label: "Mentions" },
|
||||
{ id: "zaps", label: "Zaps" },
|
||||
];
|
||||
|
||||
const GROUPS = [
|
||||
{ id: "unread", label: "Unread" },
|
||||
{ id: "new", label: "New" },
|
||||
];
|
||||
|
||||
const GROUP_EMPTY_COPY = {
|
||||
unread: "No unread notifications.",
|
||||
new: "No new notifications.",
|
||||
};
|
||||
|
||||
function isElement(value) {
|
||||
return Boolean(value && typeof value === "object" && value.nodeType === 1);
|
||||
}
|
||||
|
||||
export function NotificationItem({ document: doc, notice = {}, onSelect } = {}) {
|
||||
if (!doc) {
|
||||
throw new Error("NotificationItem requires a document reference.");
|
||||
}
|
||||
|
||||
const item = createElement(doc, "button", "dm-notification-item");
|
||||
item.type = "button";
|
||||
if (notice.variant) {
|
||||
item.classList.add(`dm-notification-item--${notice.variant}`);
|
||||
}
|
||||
if (notice.id) {
|
||||
item.dataset.noticeId = notice.id;
|
||||
}
|
||||
|
||||
const iconSlot = createElement(doc, "span", "dm-notification-item__icon");
|
||||
if (notice.icon) {
|
||||
if (isElement(notice.icon)) {
|
||||
iconSlot.appendChild(notice.icon);
|
||||
} else if (typeof notice.icon === "string") {
|
||||
iconSlot.textContent = notice.icon;
|
||||
}
|
||||
}
|
||||
|
||||
const body = createElement(doc, "div", "dm-notification-item__body");
|
||||
if (notice.title) {
|
||||
const title = createElement(
|
||||
doc,
|
||||
"div",
|
||||
"dm-notification-item__title",
|
||||
notice.title,
|
||||
);
|
||||
body.appendChild(title);
|
||||
}
|
||||
const message = createElement(
|
||||
doc,
|
||||
"div",
|
||||
"dm-notification-item__message",
|
||||
notice.message || "",
|
||||
);
|
||||
body.appendChild(message);
|
||||
|
||||
const meta = createElement(doc, "div", "dm-notification-item__meta");
|
||||
const timestamp = createElement(
|
||||
doc,
|
||||
"time",
|
||||
"dm-notification-item__timestamp",
|
||||
notice.timestamp || "",
|
||||
);
|
||||
if (notice.timestampISO) {
|
||||
timestamp.dateTime = notice.timestampISO;
|
||||
}
|
||||
meta.appendChild(timestamp);
|
||||
|
||||
item.appendChild(iconSlot);
|
||||
item.appendChild(body);
|
||||
item.appendChild(meta);
|
||||
|
||||
if (typeof onSelect === "function") {
|
||||
item.addEventListener("click", () => {
|
||||
onSelect(notice);
|
||||
});
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
export function NotificationCenter({
|
||||
document: doc,
|
||||
notices = [],
|
||||
activeFilter = "all",
|
||||
onFilterSelect,
|
||||
onNoticeSelect,
|
||||
} = {}) {
|
||||
if (!doc) {
|
||||
throw new Error("NotificationCenter requires a document reference.");
|
||||
}
|
||||
|
||||
const root = createElement(doc, "section", "dm-notification-center");
|
||||
let currentFilter = activeFilter;
|
||||
|
||||
if (!notices.length) {
|
||||
const placeholder = createElement(
|
||||
const filterBar = createElement(doc, "div", "dm-notification-center__filters");
|
||||
const filterButtons = new Map();
|
||||
|
||||
const updateFilterState = (nextFilter) => {
|
||||
currentFilter = nextFilter;
|
||||
filterButtons.forEach((button, filterId) => {
|
||||
const isActive = filterId === currentFilter;
|
||||
button.classList.toggle("dm-notification-center__filter-button--active", isActive);
|
||||
button.setAttribute("aria-pressed", isActive ? "true" : "false");
|
||||
});
|
||||
renderGroups();
|
||||
};
|
||||
|
||||
FILTERS.forEach((filter) => {
|
||||
const button = createElement(
|
||||
doc,
|
||||
"div",
|
||||
"dm-notification-center__empty",
|
||||
"You're all caught up.",
|
||||
"button",
|
||||
"dm-notification-center__filter-button",
|
||||
filter.label,
|
||||
);
|
||||
root.appendChild(placeholder);
|
||||
return root;
|
||||
}
|
||||
|
||||
notices.forEach((notice) => {
|
||||
const item = createElement(doc, "div", "dm-notification-center__item");
|
||||
if (notice.variant) {
|
||||
item.classList.add(`dm-notification-center__item--${notice.variant}`);
|
||||
}
|
||||
item.textContent = notice.message || "";
|
||||
root.appendChild(item);
|
||||
button.type = "button";
|
||||
button.dataset.filterId = filter.id;
|
||||
button.setAttribute("aria-pressed", "false");
|
||||
button.addEventListener("click", () => {
|
||||
if (filter.id === currentFilter) {
|
||||
return;
|
||||
}
|
||||
updateFilterState(filter.id);
|
||||
if (typeof onFilterSelect === "function") {
|
||||
onFilterSelect(filter.id);
|
||||
}
|
||||
});
|
||||
filterButtons.set(filter.id, button);
|
||||
filterBar.appendChild(button);
|
||||
});
|
||||
|
||||
const groupsContainer = createElement(doc, "div", "dm-notification-center__groups");
|
||||
|
||||
const getFilteredNotices = () => {
|
||||
if (currentFilter === "all") {
|
||||
return notices;
|
||||
}
|
||||
return notices.filter((notice) => notice.type === currentFilter);
|
||||
};
|
||||
|
||||
const renderGroups = () => {
|
||||
groupsContainer.innerHTML = "";
|
||||
const filteredNotices = getFilteredNotices();
|
||||
const groupMap = new Map();
|
||||
|
||||
filteredNotices.forEach((notice) => {
|
||||
const groupId = notice.group || "new";
|
||||
if (!groupMap.has(groupId)) {
|
||||
groupMap.set(groupId, []);
|
||||
}
|
||||
groupMap.get(groupId).push(notice);
|
||||
});
|
||||
|
||||
GROUPS.forEach((group) => {
|
||||
const groupSection = createElement(
|
||||
doc,
|
||||
"section",
|
||||
"dm-notification-center__group",
|
||||
);
|
||||
const title = createElement(
|
||||
doc,
|
||||
"div",
|
||||
"dm-notification-center__group-title",
|
||||
group.label,
|
||||
);
|
||||
const list = createElement(doc, "div", "dm-notification-center__list");
|
||||
const groupNotices = groupMap.get(group.id) || [];
|
||||
|
||||
if (!groupNotices.length) {
|
||||
list.appendChild(
|
||||
createElement(
|
||||
doc,
|
||||
"div",
|
||||
"dm-notification-center__empty",
|
||||
GROUP_EMPTY_COPY[group.id] || "No notifications.",
|
||||
),
|
||||
);
|
||||
} else {
|
||||
groupNotices.forEach((notice) => {
|
||||
list.appendChild(
|
||||
NotificationItem({
|
||||
document: doc,
|
||||
notice,
|
||||
onSelect: onNoticeSelect,
|
||||
}),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
groupSection.appendChild(title);
|
||||
groupSection.appendChild(list);
|
||||
groupsContainer.appendChild(groupSection);
|
||||
});
|
||||
};
|
||||
|
||||
root.appendChild(filterBar);
|
||||
root.appendChild(groupsContainer);
|
||||
|
||||
updateFilterState(currentFilter);
|
||||
|
||||
return root;
|
||||
}
|
||||
Reference in new issue
Block a user