initial commit

This commit is contained in:
Tholut A 2026-08-08 17:55:56 +07:00
commit 7e466e29d2
28 changed files with 17360 additions and 0 deletions

17
entrypoints/background.ts Normal file
View file

@ -0,0 +1,17 @@
import { registerService } from "@webext-core/proxy-service";
import { createTodosRepo } from "@/utils/todo-repo";
import { createBlockedSitesRepo } from "@/utils/blocked-site-repo";
import { BLOCKED_SITES_REPO_KEY, TODOS_REPO_KEY } from "@/utils/proxy-service-keys";
import { openExtensionDatabase } from "@/utils/database";
export default defineBackground(() => {
console.log('[ba-ka] starting let me focus service extension', { id: browser.runtime.id });
const idbProimise = openExtensionDatabase();
const todosRepo = createTodosRepo(idbProimise)
registerService(TODOS_REPO_KEY, todosRepo)
const blockedSitesRepo = createBlockedSitesRepo(idbProimise)
registerService(BLOCKED_SITES_REPO_KEY, blockedSitesRepo)
});

View file

@ -0,0 +1,42 @@
<script lang="ts" setup>
import stopImage from "~/assets/stop.png";
import Todo from "@/components/Todo.vue";
</script>
<template>
<div class="main">
<img class="logo" :src="stopImage" />
<h1 class="message">[go back to your work]</h1>
<Todo />
</div>
</template>
<style>
body {
margin: 0;
}
.main {
font-family: monospace;
position: fixed;
align-items: center;
text-align: center;
width: 100%;
height: 100%;
background: #222222;
color: #ffffff;
display: flex;
flex-direction: column;
justify-content: center;
z-index: 99999;
}
img.logo {
width: 25%;
}
h1.message,
img.logo {
filter: drop-shadow(0 0 1em #ffffff);
}
</style>

View file

@ -0,0 +1,56 @@
import { ContentScriptContext } from "#imports";
import App from "./App.vue";
import { featureEnableBlock } from "@/utils/storage";
import { createApp } from "vue";
import { createProxyService } from '@webext-core/proxy-service';
import { BlockedSite } from "@/utils/types";
const blockedSitesRepo = createProxyService(BLOCKED_SITES_REPO_KEY);
export default defineContentScript({
matches: ["*://*/*"],
cssInjectionMode: "ui",
async main(ctx) {
const ui = await defineOverlay(ctx);
const isBlockEnabled = await featureEnableBlock.getValue();
const currentDomain = window.location.hostname;
const blockedSites = await blockedSitesRepo.getAll()
function isOnBlockList() {
return (
blockedSites.filter(function (blockedSite: BlockedSite) {
return (blockedSite.url == currentDomain || "www." + blockedSite.url == currentDomain) && blockedSite.blocked;
}).length > 0
);
}
function injectToWebsite() {
if (!isBlockEnabled || !isOnBlockList()) return;
console.log("[ba-ka] site blocked! please go back to your work lol");
ui.mount();
}
injectToWebsite();
ctx.addEventListener(window, "wxt:locationchange", (event) => {
injectToWebsite();
});
},
});
function defineOverlay(ctx: ContentScriptContext) {
return createShadowRootUi(ctx, {
name: "let-me-focus-block",
position: "overlay",
zIndex: 9999,
onMount(container, _shadow, shadowHost) {
const app = createApp(App);
app.mount(container);
shadowHost.style.pointerEvents = "none";
return app;
},
onRemove(app) {
app?.unmount();
},
});
}

51
entrypoints/popup/App.vue Normal file
View file

@ -0,0 +1,51 @@
<script lang="ts" setup>
import ToggleOnOff from "@/components/ToggleOnOff.vue";
import Todo from "@/components/Todo.vue"
import BlockedSite from "@/components/BlockedSite.vue"
const currentMenu = ref("main")
const menuLists = [
"main",
"completed",
"blocked sites",
]
const changeMenu = (menu: string) => {
currentMenu.value = menu
}
</script>
<template>
<ToggleOnOff />
<h1>let me focus</h1>
<ul style="text-align: center;" v-for="menu in menuLists">
<li>
<button @click="changeMenu(menu)">[{{ menu }}]</button>
</li>
</ul>
<Todo v-if="currentMenu === 'main'" showInput hoverShowDeleteButton />
<Todo v-if="currentMenu === 'completed'" showOnlyCompleted showClearAllTodo />
<BlockedSite v-if="currentMenu === 'blocked sites'" />
<br/>
[{{browser.runtime.getManifest().version}}]
</template>
<style scoped>
ul {
padding: 0;
display: inline-block;
}
li {
list-style: none;
margin: 0px 5px;
}
li button {
cursor: pointer;
}
.logo {
height: 6em;
filter: drop-shadow(0 0 1em #ffffff);
}
</style>

View file

@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>let me focus</title>
<meta name="manifest.type" content="browser_action" />
</head>
<body>
<div id="app"></div>
<script type="module" src="./main.ts"></script>
</body>
</html>

View file

@ -0,0 +1,5 @@
import { createApp } from 'vue';
import './style.css';
import App from './App.vue';
createApp(App).mount('#app');

View file

@ -0,0 +1,42 @@
:root {
font-family: monospace;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: #ffffff;
background-color: #222222;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 400px;
min-height: 100vh;
}
h1 {
font-size: 2.4em;
}
button {
font-size: 1em;
font-weight: 500;
}
#app {
max-width: 400px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
@media (prefers-color-scheme: light) {
:root {
color: #222222;
background-color: #ffffff;
}
button {
background-color: #f9f9f9;
}
}