mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-06 04:42:57 +00:00
Add notification center filters and grouping
This commit is contained in:
1 parent
97043ce2c0
commit
f9c351e157
3 files changed
+317
-24
No files matched your search
+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