Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NotificationBlock: UI to show blocked posts #1582

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 49 additions & 3 deletions src/features/notificationblock.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { buildStyle } from '../utils/interface.js';
import { registerMeatballItem, unregisterMeatballItem } from '../utils/meatballs.js';
import { onNewNotifications } from '../utils/mutations.js';
import { showModal, hideModal, modalCancelButton } from '../utils/modals.js';
import { showModal, hideModal, modalCancelButton, modalCompleteButton } from '../utils/modals.js';
import { dom } from '../utils/dom.js';
import { userBlogNames } from '../utils/user.js';
import { apiFetch } from '../utils/tumblr_helpers.js';
import { userBlogNames, userBlogs } from '../utils/user.js';
import { apiFetch, navigate } from '../utils/tumblr_helpers.js';
import { notificationObject } from '../utils/react_props.js';

const storageKey = 'notificationblock.blockedPostTargetIDs';
const toOpenStorageKey = 'notificationblock.toOpen';
const meatballButtonBlockId = 'notificationblock-block';
const meatballButtonBlockLabel = 'Block notifications';
const meatballButtonUnblockId = 'notificationblock-unblock';
Expand Down Expand Up @@ -102,13 +103,58 @@ export const onStorageChanged = (changes, areaName) => {
}
};

const openPostById = async id => {
let canceled = false;
const timeoutId = setTimeout(() => showModal({
title: 'NotificationBlock',
message: [`Searching for post ${id} on your blogs. Please wait...`],
buttons: [dom('button', { class: 'red' }, { click: () => { canceled = true; } }, ['Cancel'])]
}), 500);

const sortedUserBlogs = [...userBlogs].sort((a, b) => b.posts - a.posts);
for (const { name } of sortedUserBlogs) {
try {
await apiFetch(`/v2/blog/${name}/posts/${id}`);
clearTimeout(timeoutId);
hideModal();
navigate(`/@${name}/${id}`);
return;
} catch {
if (canceled) {
hideModal();
return;
} else {
await new Promise(resolve => setTimeout(resolve, 500));
}
}
}

clearTimeout(timeoutId);
showModal({
title: 'NotificationBlock',
message: [`Failed to find and open post ${id}! It may not be one of your original posts.`],
buttons: [modalCompleteButton]
});
};

export const main = async function () {
({ [storageKey]: blockedPostTargetIDs = [] } = await browser.storage.local.get(storageKey));
styleElement.textContent = buildCss();
onNewNotifications.addListener(processNotifications);

registerMeatballItem({ id: meatballButtonBlockId, label: meatballButtonBlockLabel, onclick: onButtonClicked, postFilter: blockPostFilter });
registerMeatballItem({ id: meatballButtonUnblockId, label: meatballButtonUnblockLabel, onclick: onButtonClicked, postFilter: unblockPostFilter });

const { [toOpenStorageKey]: toOpen } = await browser.storage.local.get(toOpenStorageKey);
if (toOpen) {
browser.storage.local.remove(toOpenStorageKey);
openPostById(toOpen.blockedPostID);
} else {
const blockedPostID = new URLSearchParams(location.search).get('notificationblock-id');
if (blockedPostID) {
openPostById(blockedPostID);
}
}
};

export const clean = async function () {
Expand Down
9 changes: 8 additions & 1 deletion src/features/notificationblock.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,12 @@
"background_color": "#f5223c"
},
"help": "https://github.com/AprilSylph/XKit-Rewritten/wiki/Features#notificationblock",
"relatedTerms": [ "activity", "mute notifications", "notes" ]
"relatedTerms": [ "activity", "mute notifications", "notes" ],
"preferences": {
"manageBlockedPosts": {
"type": "iframe",
"label": "Manage posts with blocked notifications",
"src": "/features/notificationblock/options/index.html"
}
}
}
69 changes: 69 additions & 0 deletions src/features/notificationblock/options/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
:root {
--black: 21, 20, 25;
--white: 255, 255, 255;
--grey: 207, 207, 216;
--accent: 10, 132, 255;
}

@media (prefers-color-scheme: dark) {
:root {
--black: 251, 251, 254;
--white: 66, 65, 77;
--grey: 91, 91, 102;
--accent: 54, 213, 255;
}
}

html {
font-size: 14px;
scrollbar-color: rgb(var(--grey)) transparent;
scrollbar-width: thin;
overflow-y: hidden;
}

body {
background-color: rgb(var(--white));
color: rgb(var(--black));
font-family: "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
font-size: 100%;
-webkit-user-select: none;
user-select: none;
}

header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin-bottom: 1em;
}

#notification-blocked-count {
font-weight: bold;
}

#notification-blocked-posts {
padding: 0;
border-bottom: 1px solid rgb(var(--grey));
margin: 0;
}

.notification-blocked-post {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 1ch 0;
border-top: 1px solid rgb(var(--grey));
}

.notification-blocked-post button {
padding: 0;
border: none;

appearance: none;
background-color: transparent;
color: rgb(var(--accent));
cursor: pointer;
font-weight: bold;
}
28 changes: 28 additions & 0 deletions src/features/notificationblock/options/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XKit: Manage posts with blocked notifications</title>
<link rel="icon" href="/icons/128.png" type="image/png">
<link rel="stylesheet" href="/lib/normalize.min.css">
<link rel="stylesheet" href="index.css">
<script src="/action/resize_frames.js" defer></script>
<script src="/lib/browser-polyfill.min.js" defer></script>
<script src="index.js" defer></script>
</head>
<body>
<template id="notification-blocked-post">
<li class="notification-blocked-post">
<a target="_blank"><span></span></a>
<button data-post-id="">Remove</button>
</li>
</template>
<main>
<header>
<span id="notification-blocked-count"></span>
</header>
<ul id="notification-blocked-posts"></ul>
</main>
</body>
</html>
53 changes: 53 additions & 0 deletions src/features/notificationblock/options/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
const postsBlockedCount = document.getElementById('notification-blocked-count');
const blockedPostList = document.getElementById('notification-blocked-posts');
const blockedPostTemplate = document.getElementById('notification-blocked-post');

const storageKey = 'notificationblock.blockedPostTargetIDs';
const toOpenStorageKey = 'notificationblock.toOpen';

const unblockPost = async function ({ currentTarget }) {
let { [storageKey]: blockedPostRootIDs = [] } = await browser.storage.local.get(storageKey);

blockedPostRootIDs = blockedPostRootIDs.filter(id => id !== currentTarget.dataset.postId);
await browser.storage.local.set({ [storageKey]: blockedPostRootIDs });

currentTarget.remove();
};

const renderBlocked = async function () {
const { [storageKey]: blockedPostRootIDs = [] } = await browser.storage.local.get(storageKey);

postsBlockedCount.textContent = `${blockedPostRootIDs.length} ${blockedPostRootIDs.length === 1 ? 'post' : 'posts'} with blocked notifications`;
blockedPostList.textContent = '';

for (const blockedPostID of blockedPostRootIDs) {
const templateClone = blockedPostTemplate.content.cloneNode(true);
const anchorElement = templateClone.querySelector('a');
const spanElement = templateClone.querySelector('span');
const unblockButton = templateClone.querySelector('button');

spanElement.textContent = blockedPostID;
unblockButton.dataset.postId = blockedPostID;
unblockButton.addEventListener('click', unblockPost);

anchorElement.href = `https://www.tumblr.com/?notificationblock-id=${blockedPostID}`;

anchorElement.addEventListener('click', async event => {
event.preventDefault();
await browser.storage.local.set({
[toOpenStorageKey]: { blockedPostID }
});
window.open('https://www.tumblr.com/');
});

blockedPostList.append(templateClone);
}
};

browser.storage.onChanged.addListener((changes, areaName) => {
if (areaName === 'local' && Object.keys(changes).includes(storageKey)) {
renderBlocked();
}
});

renderBlocked();