From 4c0a60b14a451796d986251b97b0e1ed017dded9 Mon Sep 17 00:00:00 2001 From: cupcakearmy Date: Tue, 23 Nov 2021 14:12:38 +0100 Subject: [PATCH] dismiss & use svelte in client --- manifest.json | 3 +- src/background/index.js | 9 +++++ src/client/App.svelte | 85 ++++++++++++++++++++++++++++++++++++++++ src/client/blocked.js | 17 ++++++++ src/client/dismiss.js | 20 ++++++++++ src/client/index.css | 33 ---------------- src/client/index.js | 48 ++--------------------- src/client/reporter.js | 19 +++++++++ src/shared/db.js | 1 + src/shared/lib.js | 6 +++ src/shared/validation.js | 11 +++++- 11 files changed, 171 insertions(+), 81 deletions(-) create mode 100644 src/client/App.svelte create mode 100644 src/client/blocked.js create mode 100644 src/client/dismiss.js delete mode 100644 src/client/index.css create mode 100644 src/client/reporter.js diff --git a/manifest.json b/manifest.json index a37b663..4bd42fa 100644 --- a/manifest.json +++ b/manifest.json @@ -30,8 +30,7 @@ "content_scripts": [ { "matches": [""], - "js": ["./src/client/index.js"], - "css": ["./src/client/index.css"] + "js": ["./src/client/index.js"] } ], "web_accessible_resources": ["./icons/watch.png", "./icons/watch-alt.png", "./src/dashboard/index.html"] diff --git a/src/background/index.js b/src/background/index.js index 938640c..8ffa0b9 100644 --- a/src/background/index.js +++ b/src/background/index.js @@ -4,6 +4,7 @@ import dayjs from 'dayjs' import { dashboard } from '../shared/utils' import { insertLog, normalizeTimestamp, DB } from '../shared/db' import { getSettingsWithDefaults, getUsageForHost, percentagesToBool } from '../shared/lib' +import { DismissValidator, checkForErrors } from '../shared/validation' browser.browserAction.onClicked.addListener(() => browser.tabs.create({ url: dashboard, active: true })) @@ -65,5 +66,13 @@ browser.runtime.onMessage.addListener((message, sender, sendResponse) => { case 'report': DB.settings.put({ key: 'lastActivity', value: new Date() }) break + case 'dismiss': + const entry = { + host: message.host, + timestamp: new Date(), + duration: message.duration, + } + if (!checkForErrors(DismissValidator, entry)) DB.dismiss.put(entry) + break } }) diff --git a/src/client/App.svelte b/src/client/App.svelte new file mode 100644 index 0000000..8776707 --- /dev/null +++ b/src/client/App.svelte @@ -0,0 +1,85 @@ + + +
+
+

Overtime

+
You have no time left on this website.
+
+
+
+ dismiss for... +
+ +
+
+
+ + diff --git a/src/client/blocked.js b/src/client/blocked.js new file mode 100644 index 0000000..853d80b --- /dev/null +++ b/src/client/blocked.js @@ -0,0 +1,17 @@ +import browser from 'webextension-polyfill' +import { readable } from 'svelte/store' + +async function check(set) { + if (window.document.hidden) return + const isBlocked = await browser.runtime.sendMessage({ + type: 'check', + host: window.location.host, + }) + set(isBlocked) +} + +export const blocked = new readable(false, (set) => { + check(set) + const interval = setInterval(() => check(set), 1000) + return () => clearInterval(interval) +}) diff --git a/src/client/dismiss.js b/src/client/dismiss.js new file mode 100644 index 0000000..dc98946 --- /dev/null +++ b/src/client/dismiss.js @@ -0,0 +1,20 @@ +import dayjs from 'dayjs' +import * as duration from 'dayjs/plugin/duration' +dayjs.extend(duration) + +import browser from 'webextension-polyfill' + +export const buttons = [ + { label: '1 minute', duration: dayjs.duration({ minutes: 1 }) }, + { label: '5 minutes', duration: dayjs.duration({ minutes: 5 }) }, + { label: '15 minutes', duration: dayjs.duration({ minutes: 15 }) }, + { label: '1 hours', duration: dayjs.duration({ hours: 1 }) }, +] + +export function dismiss(duration) { + browser.runtime.sendMessage({ + type: 'dismiss', + duration: duration.asMilliseconds(), + host: window.location.host, + }) +} diff --git a/src/client/index.css b/src/client/index.css deleted file mode 100644 index 4b45e3b..0000000 --- a/src/client/index.css +++ /dev/null @@ -1,33 +0,0 @@ -.ora--wrapper { - display: none; - position: fixed; - color: #111; - top: 0; - left: 0; - width: 100vw; - height: 100vh; - background-color: #eee; - z-index: 999999999; - font-size: 1rem; - padding: 1rem; - text-align: center; - user-select: none; -} - -@media (prefers-color-scheme: dark) { - .ora--wrapper { - background-color: #111; - color: #eee; - } -} - -.ora--wrapper div { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', - 'Helvetica Neue', sans-serif; - margin: 3rem auto; - width: 100%; -} - -.ora--wrapper div h1 { - margin-bottom: 0.5rem; -} diff --git a/src/client/index.js b/src/client/index.js index 6f41c33..ae83a4a 100644 --- a/src/client/index.js +++ b/src/client/index.js @@ -1,45 +1,5 @@ -import browser from 'webextension-polyfill' +import App from './App.svelte' -let wrapper -let lastReported = 0 - -function init() { - wrapper = window.document.createElement('div') - wrapper.classList.add('ora--wrapper') - wrapper.classList.add('hidden') - - const inner = window.document.createElement('div') - inner.innerHTML = ` -

Overtime ⏱

-

You have no time left on this website 🥺

- ` - wrapper.appendChild(inner) - window.document.body.appendChild(wrapper) -} - -async function check() { - if (window.document.hidden) return - const isBlocked = await browser.runtime.sendMessage({ - type: 'check', - host: window.location.host, - }) - wrapper.style.display = isBlocked ? 'initial' : 'none' -} - -init() -check() -setInterval(check, 2000) - -function logActivity() { - const now = Date.now() - // Limit reports to once every second - if (now - lastReported < 1000) return - lastReported = now - browser.runtime.sendMessage({ - type: 'report', - }) -} - -window.document.addEventListener('mousemove', logActivity, false) -window.document.addEventListener('keydown', logActivity, false) -window.document.addEventListener('scroll', logActivity, false) +wrapper = window.document.createElement('div') +window.document.body.appendChild(wrapper) +new App({ target: wrapper }) diff --git a/src/client/reporter.js b/src/client/reporter.js new file mode 100644 index 0000000..fb0b063 --- /dev/null +++ b/src/client/reporter.js @@ -0,0 +1,19 @@ +import browser from 'webextension-polyfill' + +let lastReported = 0 + +function logActivity() { + const now = Date.now() + // Limit reports to once every second + if (now - lastReported < 1000) return + lastReported = now + browser.runtime.sendMessage({ + type: 'report', + }) +} + +export function init() { + window.document.addEventListener('mousemove', logActivity, false) + window.document.addEventListener('keydown', logActivity, false) + window.document.addEventListener('scroll', logActivity, false) +} diff --git a/src/shared/db.js b/src/shared/db.js index c635d17..80a5e87 100644 --- a/src/shared/db.js +++ b/src/shared/db.js @@ -18,6 +18,7 @@ DB.version(2).stores({ DB.version(3).stores({ settings: `key, value`, + dismiss: `host, timestamp, duration`, }) export function normalizeTimestamp(timestamp) { diff --git a/src/shared/lib.js b/src/shared/lib.js index d64e42a..8e401b2 100644 --- a/src/shared/lib.js +++ b/src/shared/lib.js @@ -52,6 +52,12 @@ export function getUsageForRules(host, rules) { } export async function getUsageForHost(host) { + const dismiss = await DB.dismiss.where({ host }).first() + if (dismiss) { + const isDismissed = dj().isBefore(dj(dismiss.timestamp).add(dismiss.duration, 'ms')) + if (isDismissed) return [] + } + const limit = await DB.limits.where({ host }).first() if (!limit) return [] return await Promise.all(getUsageForRules(host, limit.rules)) diff --git a/src/shared/validation.js b/src/shared/validation.js index 73c4464..d12a8c1 100644 --- a/src/shared/validation.js +++ b/src/shared/validation.js @@ -20,6 +20,12 @@ export const LogValidator = Joi.object({ timestamp: Joi.date(), }) +export const DismissValidator = Joi.object({ + host: Joi.string(), + timestamp: Joi.date(), + duration: Joi.number(), +}) + export const SettingsValidator = Joi.object({ lastActivity: Joi.date() .default(() => new Date()) @@ -29,9 +35,10 @@ export const SettingsValidator = Joi.object({ }) export const DBValidator = Joi.object({ - limits: Joi.array().items(LimitValidator), - logs: Joi.array().items(LogValidator), + limits: Joi.array().items(LimitValidator).optional(), + logs: Joi.array().items(LogValidator).optional(), settings: SettingsValidator.optional(), + dismiss: Joi.array().items(DismissValidator).optional(), }) export function checkForErrors(validator, data) {