mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 16:02:26 +00:00
220 lines
5.5 KiB
JavaScript
220 lines
5.5 KiB
JavaScript
function createElement(doc, tag, className, text) {
|
|
const element = doc.createElement(tag);
|
|
if (className) {
|
|
element.className = className;
|
|
}
|
|
if (typeof text === "string") {
|
|
element.textContent = text;
|
|
}
|
|
return element;
|
|
}
|
|
|
|
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;
|
|
|
|
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,
|
|
"button",
|
|
"dm-notification-center__filter-button",
|
|
filter.label,
|
|
);
|
|
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;
|
|
}
|