feat: rewrite to solidjs
This commit is contained in:
parent
74c6215c27
commit
afa2db26e7
21 changed files with 1074 additions and 1835 deletions
48
components/BlockedSite.css
Normal file
48
components/BlockedSite.css
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
.container {
|
||||||
|
min-width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
list-style: none;
|
||||||
|
text-align: left;
|
||||||
|
font-size: 14pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
li label {
|
||||||
|
display: block;
|
||||||
|
border: 1px solid #ffffff00;
|
||||||
|
}
|
||||||
|
|
||||||
|
li label:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
li .button-delete {
|
||||||
|
display: none;
|
||||||
|
font-size: 10pt;
|
||||||
|
float: right;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
li:hover .button-delete {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-input input,
|
||||||
|
.form-input button {
|
||||||
|
width: 100%;
|
||||||
|
padding: 2px 4px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-input input {
|
||||||
|
font-size: 12pt;
|
||||||
|
box-sizing: border-box;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
}
|
||||||
89
components/BlockedSite.tsx
Normal file
89
components/BlockedSite.tsx
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
import { type Component, createResource, createSignal } from "solid-js";
|
||||||
|
import "./BlockedSite.css";
|
||||||
|
|
||||||
|
import { BLOCKED_SITES_REPO_KEY } from "@/utils/proxy-service-keys";
|
||||||
|
import type { BlockedSite } from "@/utils/types";
|
||||||
|
import { createProxyService } from "@webext-core/proxy-service";
|
||||||
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
|
||||||
|
const blockedSitesRepo = createProxyService(BLOCKED_SITES_REPO_KEY);
|
||||||
|
|
||||||
|
export const BlockedSite: Component = (props) => {
|
||||||
|
const [blockedSites, { refetch }] = createResource(blockedSitesRepo.getAll);
|
||||||
|
const [inputNewSite, setInputNewSite] = createSignal("");
|
||||||
|
|
||||||
|
const createBlockedSite = async () => {
|
||||||
|
const url = inputNewSite();
|
||||||
|
if (!url) return;
|
||||||
|
if (!url.trim()) return;
|
||||||
|
const generateTodoId = uuidv4();
|
||||||
|
await blockedSitesRepo.insert({
|
||||||
|
id: generateTodoId,
|
||||||
|
url: url,
|
||||||
|
blocked: true,
|
||||||
|
});
|
||||||
|
setInputNewSite("");
|
||||||
|
await refetch();
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateBlockedSite = async (
|
||||||
|
blockedSite: BlockedSite,
|
||||||
|
isBlocked: boolean,
|
||||||
|
) => {
|
||||||
|
blockedSite.blocked = isBlocked;
|
||||||
|
await blockedSitesRepo.update(blockedSite);
|
||||||
|
await refetch();
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteBlockedSite = async (blockedSite: BlockedSite) => {
|
||||||
|
await blockedSitesRepo.delete(blockedSite);
|
||||||
|
await refetch();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div class="container">
|
||||||
|
<h2>[blocked sites]</h2>
|
||||||
|
<div class="form-input">
|
||||||
|
<input
|
||||||
|
placeholder="ba-ka.org"
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
// key code 13 is enter
|
||||||
|
if (e.keyCode === 13) {
|
||||||
|
createBlockedSite();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onInput={(e) => setInputNewSite(e.currentTarget.value)}
|
||||||
|
type="input"
|
||||||
|
/>
|
||||||
|
<button onClick={() => createBlockedSite()}>[add site]</button>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<For each={blockedSites()}>
|
||||||
|
{(blockedSite) => {
|
||||||
|
return (
|
||||||
|
<li>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={blockedSite.blocked}
|
||||||
|
onChange={(e) =>
|
||||||
|
updateBlockedSite(blockedSite, e.currentTarget.checked)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{blockedSite.url}
|
||||||
|
<button
|
||||||
|
class="button-delete"
|
||||||
|
onClick={() => deleteBlockedSite(blockedSite)}
|
||||||
|
>
|
||||||
|
x
|
||||||
|
</button>
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -1,114 +0,0 @@
|
||||||
<script lang="ts" setup>
|
|
||||||
import { BLOCKED_SITES_REPO_KEY } from "@/utils/proxy-service-keys";
|
|
||||||
import { BlockedSite } from "@/utils/types";
|
|
||||||
import { createProxyService } from '@webext-core/proxy-service';
|
|
||||||
import { v4 as uuidv4 } from "uuid"
|
|
||||||
|
|
||||||
const blockedSitesRepo = createProxyService(BLOCKED_SITES_REPO_KEY);
|
|
||||||
|
|
||||||
const props = defineProps<{}>()
|
|
||||||
|
|
||||||
const blockedSites = ref<BlockedSite[]>([]);
|
|
||||||
const inputNewSite = ref<string | null>();
|
|
||||||
|
|
||||||
const refreshBlockedSite = async () => {
|
|
||||||
blockedSites.value = await blockedSitesRepo.getAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
onBeforeMount(async () => refreshBlockedSite())
|
|
||||||
|
|
||||||
const insertBlockedSite = async () => {
|
|
||||||
if (!inputNewSite.value) return
|
|
||||||
if (!inputNewSite.value.trim()) return
|
|
||||||
const generateTodoId = uuidv4()
|
|
||||||
await blockedSitesRepo.insert({
|
|
||||||
id: generateTodoId,
|
|
||||||
url: inputNewSite.value,
|
|
||||||
blocked: true
|
|
||||||
})
|
|
||||||
inputNewSite.value = null
|
|
||||||
refreshBlockedSite()
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateBlockedSite = async (blockedSite: BlockedSite) => {
|
|
||||||
await blockedSitesRepo.update(toRaw(blockedSite))
|
|
||||||
refreshBlockedSite()
|
|
||||||
}
|
|
||||||
|
|
||||||
const deleteBlockedSite = async (blockedSite: BlockedSite) => {
|
|
||||||
await blockedSitesRepo.delete(toRaw(blockedSite))
|
|
||||||
refreshBlockedSite()
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="container">
|
|
||||||
<h2>[blocked sites]</h2>
|
|
||||||
<div class="form-input">
|
|
||||||
<input @keydown.enter="insertBlockedSite" v-model="inputNewSite" placeholder="ba-ka.org" type="input"/>
|
|
||||||
<button @click="insertBlockedSite">[add site]</button>
|
|
||||||
</div>
|
|
||||||
<br/>
|
|
||||||
<div v-if="blockedSites.length === 0">no blocked sites :(</div>
|
|
||||||
<ul v-else v-for="blockedSite in blockedSites">
|
|
||||||
<li :key="blockedSite.id">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" @change="updateBlockedSite(blockedSite)" v-model="blockedSite.blocked" :id="blockedSite.id"/>
|
|
||||||
{{ blockedSite.url }}
|
|
||||||
<button class="button-delete" @click="deleteBlockedSite(blockedSite)">x</button>
|
|
||||||
</label>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.container {
|
|
||||||
min-width: 300px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
list-style: none;
|
|
||||||
text-align: left;
|
|
||||||
font-size: 14pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
li label {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
li label:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
border: 1px solid #ffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
li .button-delete {
|
|
||||||
display: none;
|
|
||||||
padding: 1px 4px;
|
|
||||||
font-size: 10pt;
|
|
||||||
float: right
|
|
||||||
}
|
|
||||||
|
|
||||||
li:hover .button-delete {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-input input,
|
|
||||||
.form-input button {
|
|
||||||
width: 100%;
|
|
||||||
padding: 2px 4px;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-input input {
|
|
||||||
font-size: 12pt;
|
|
||||||
box-sizing: border-box;
|
|
||||||
-webkit-box-sizing:border-box;
|
|
||||||
-moz-box-sizing: border-box;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
15
components/MainToggle.css
Normal file
15
components/MainToggle.css
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
.button-toggle {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
.button-toggle .logo {
|
||||||
|
width: 80%;
|
||||||
|
height: 80%;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-toggle .logo-on {
|
||||||
|
filter: drop-shadow(0 0 1em #ffffff);
|
||||||
|
}
|
||||||
28
components/MainToggle.tsx
Normal file
28
components/MainToggle.tsx
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { createSignal, onMount } from "solid-js";
|
||||||
|
import { featureEnableBlock } from "@/utils/storage";
|
||||||
|
import "./MainToggle.css";
|
||||||
|
|
||||||
|
export const MainToggle = (props) => {
|
||||||
|
const [isEnabled, setIsEnabled] = createSignal(false);
|
||||||
|
onMount(async () => {
|
||||||
|
const getFeatureEnable = await featureEnableBlock.getValue();
|
||||||
|
setIsEnabled(getFeatureEnable);
|
||||||
|
});
|
||||||
|
const toggleOnOff = () => {
|
||||||
|
setIsEnabled(!isEnabled());
|
||||||
|
featureEnableBlock.setValue(isEnabled());
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<button class="button-toggle" onClick={() => toggleOnOff()}>
|
||||||
|
<img
|
||||||
|
src="/icon/128.png"
|
||||||
|
class={isEnabled() ? "logo logo-on" : "logo"}
|
||||||
|
alt="let me focus logo"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<br />
|
||||||
|
{isEnabled() ? "[on]" : "[off]"}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
128
components/Todo.tsx
Normal file
128
components/Todo.tsx
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
import {
|
||||||
|
type Component,
|
||||||
|
createResource,
|
||||||
|
createSignal,
|
||||||
|
createEffect,
|
||||||
|
} from "solid-js";
|
||||||
|
import "./BlockedSite.css";
|
||||||
|
|
||||||
|
import { TODOS_REPO_KEY } from "@/utils/proxy-service-keys";
|
||||||
|
import type { Todo } from "@/utils/types";
|
||||||
|
import { createProxyService } from "@webext-core/proxy-service";
|
||||||
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
|
||||||
|
const todosRepo = createProxyService(TODOS_REPO_KEY);
|
||||||
|
|
||||||
|
export const Todo: Component = (props) => {
|
||||||
|
const [rawTodos, { refetch }] = createResource(todosRepo.getAll, []);
|
||||||
|
const [todos, setTodos] = createSignal([]);
|
||||||
|
const [inputNewTodo, setInputNewTodo] = createSignal("");
|
||||||
|
|
||||||
|
createEffect(async () => {
|
||||||
|
const allTodos = rawTodos();
|
||||||
|
if (!allTodos) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log("OI");
|
||||||
|
const filteredTodos = allTodos.filter(
|
||||||
|
(todo: Todo) =>
|
||||||
|
(props.showCompleted && todo.completed) ||
|
||||||
|
(props.showOnlyCompleted && todo.completed) ||
|
||||||
|
(!props.showOnlyCompleted && !todo.completed),
|
||||||
|
);
|
||||||
|
setTodos(filteredTodos);
|
||||||
|
});
|
||||||
|
|
||||||
|
const createTodo = async () => {
|
||||||
|
const name = inputNewTodo();
|
||||||
|
if (!name) return;
|
||||||
|
if (!name.trim()) return;
|
||||||
|
const generateTodoId = uuidv4();
|
||||||
|
await todosRepo.insert({
|
||||||
|
id: generateTodoId,
|
||||||
|
name: name,
|
||||||
|
completed: false,
|
||||||
|
});
|
||||||
|
setInputNewTodo("");
|
||||||
|
await refetch();
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateTodo = async (todo: Todo, isCompleted: boolean) => {
|
||||||
|
todo.completed = isCompleted;
|
||||||
|
await todosRepo.update(todo);
|
||||||
|
await refetch();
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteTodo = async (todo: Todo) => {
|
||||||
|
await todosRepo.delete(todo);
|
||||||
|
await refetch();
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearAllCompletedTodo = async () => {
|
||||||
|
const allTodos = await todosRepo.getAll();
|
||||||
|
const completedTodos = allTodos.filter((todo) => todo.completed);
|
||||||
|
const deletePromises = completedTodos.map((todo) => todosRepo.delete(todo));
|
||||||
|
await Promise.all(deletePromises);
|
||||||
|
refetch();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div class="container">
|
||||||
|
{props.showOnlyCompleted ? (
|
||||||
|
<h2>[completed todos]</h2>
|
||||||
|
) : (
|
||||||
|
<h2>[todos]</h2>
|
||||||
|
)}
|
||||||
|
{props.showInput && (
|
||||||
|
<div class="form-input">
|
||||||
|
<input
|
||||||
|
placeholder="playing skateboard at 5am"
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
// key code 13 is enter
|
||||||
|
if (e.keyCode === 13) {
|
||||||
|
createTodo();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onInput={(e) => setInputNewTodo(e.currentTarget.value)}
|
||||||
|
type="input"
|
||||||
|
/>
|
||||||
|
<button onClick={() => createTodo()}>[add todo]</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{props.showClearAllTodo && (
|
||||||
|
<div>
|
||||||
|
<button onClick={() => clearAllCompletedTodo()}>
|
||||||
|
[clear all completed todos]
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<br />
|
||||||
|
<For each={todos()}>
|
||||||
|
{(todo) => {
|
||||||
|
return (
|
||||||
|
<li>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={todo.completed}
|
||||||
|
onChange={(e) => updateTodo(todo, e.currentTarget.checked)}
|
||||||
|
/>
|
||||||
|
{todo.name}
|
||||||
|
{props.hoverShowDeleteButton && (
|
||||||
|
<button
|
||||||
|
class="button-delete"
|
||||||
|
onClick={() => deleteTodo(todo)}
|
||||||
|
>
|
||||||
|
x
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -1,140 +0,0 @@
|
||||||
<script lang="ts" setup>
|
|
||||||
import { TODOS_REPO_KEY } from "@/utils/proxy-service-keys";
|
|
||||||
import { Todo } from "@/utils/types";
|
|
||||||
import { createProxyService } from '@webext-core/proxy-service';
|
|
||||||
import { v4 as uuidv4 } from "uuid"
|
|
||||||
|
|
||||||
const todosRepo = createProxyService(TODOS_REPO_KEY);
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
showCompleted?: boolean,
|
|
||||||
showOnlyCompleted?: boolean,
|
|
||||||
showInput?: boolean,
|
|
||||||
hoverShowDeleteButton?: boolean,
|
|
||||||
showClearAllTodo?: boolean
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const todos = ref<Todo[]>([]);
|
|
||||||
const inputNewTodo = ref<string | null>();
|
|
||||||
|
|
||||||
const refreshTodo = async () => {
|
|
||||||
const allTodos = await todosRepo.getAll();
|
|
||||||
todos.value = allTodos.filter(
|
|
||||||
(todo: Todo) =>
|
|
||||||
(props.showCompleted && todo.completed) ||
|
|
||||||
(props.showOnlyCompleted && todo.completed) ||
|
|
||||||
(!props.showOnlyCompleted && !todo.completed)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
onBeforeMount(async () => refreshTodo())
|
|
||||||
|
|
||||||
const insertTodo = async () => {
|
|
||||||
if (!inputNewTodo.value) return
|
|
||||||
if (!inputNewTodo.value.trim()) return
|
|
||||||
const generateTodoId = uuidv4()
|
|
||||||
await todosRepo.insert({
|
|
||||||
id: generateTodoId,
|
|
||||||
name: inputNewTodo.value,
|
|
||||||
completed: false
|
|
||||||
})
|
|
||||||
inputNewTodo.value = null
|
|
||||||
refreshTodo()
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateTodo = async (todo: Todo) => {
|
|
||||||
await todosRepo.update(toRaw(todo))
|
|
||||||
refreshTodo()
|
|
||||||
}
|
|
||||||
|
|
||||||
const deleteTodo = async (todo: Todo) => {
|
|
||||||
await todosRepo.delete(toRaw(todo))
|
|
||||||
refreshTodo()
|
|
||||||
}
|
|
||||||
|
|
||||||
const clearAllCompletedTodo = async () => {
|
|
||||||
const allTodos = await todosRepo.getAll()
|
|
||||||
const completedTodos = allTodos.filter((todo) => todo.completed)
|
|
||||||
const deletePromises = completedTodos.map((todo) => todosRepo.delete(todo))
|
|
||||||
await Promise.all(deletePromises)
|
|
||||||
refreshTodo()
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="container">
|
|
||||||
<h2 v-if="props.showOnlyCompleted">[completed todos]</h2>
|
|
||||||
<h2 v-if="!props.showOnlyCompleted">[todos]</h2>
|
|
||||||
<div v-if="showInput" class="form-input">
|
|
||||||
<input @keydown.enter="insertTodo" v-model="inputNewTodo" placeholder="playing skateboard at 5am" type="input"/>
|
|
||||||
<button @click="insertTodo">[add todo]</button>
|
|
||||||
</div>
|
|
||||||
<div v-if="showClearAllTodo">
|
|
||||||
<button @click="clearAllCompletedTodo">[clear all completed todos]</button>
|
|
||||||
</div>
|
|
||||||
<br/>
|
|
||||||
<div v-if="todos.length === 0">no todos :D</div>
|
|
||||||
<ul v-else v-for="todo in todos">
|
|
||||||
<li :class="{ completed: todo.completed }" :key="todo.id">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" @change="updateTodo(todo)" v-model="todo.completed" :id="todo.id"/>
|
|
||||||
{{ todo.name }}
|
|
||||||
<button class="button-delete" v-if="props.hoverShowDeleteButton" @click="deleteTodo(todo)">x</button>
|
|
||||||
</label>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.container {
|
|
||||||
min-width: 300px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
list-style: none;
|
|
||||||
text-align: left;
|
|
||||||
font-size: 14pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
li label {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
li label:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
li.completed {
|
|
||||||
text-decoration: line-through;
|
|
||||||
}
|
|
||||||
|
|
||||||
li .button-delete {
|
|
||||||
display: none;
|
|
||||||
padding: 1px 4px;
|
|
||||||
font-size: 10pt;
|
|
||||||
float: right
|
|
||||||
}
|
|
||||||
|
|
||||||
li:hover .button-delete {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-input input,
|
|
||||||
.form-input button {
|
|
||||||
width: 100%;
|
|
||||||
padding: 2px 4px;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-input input {
|
|
||||||
font-size: 12pt;
|
|
||||||
box-sizing: border-box;
|
|
||||||
-webkit-box-sizing:border-box;
|
|
||||||
-moz-box-sizing: border-box;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import { featureEnableBlock } from "@/utils/storage"
|
|
||||||
|
|
||||||
const isEnabled = ref(false)
|
|
||||||
let unwatchStorage: (() => void | undefined)
|
|
||||||
|
|
||||||
onMounted(async() => {
|
|
||||||
isEnabled.value = await featureEnableBlock.getValue()
|
|
||||||
|
|
||||||
unwatchStorage = featureEnableBlock.watch((newValue) => {
|
|
||||||
if (newValue !== isEnabled.value) {
|
|
||||||
isEnabled.value = newValue
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
if (unwatchStorage) unwatchStorage();
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(isEnabled, async (newValue) => {
|
|
||||||
await featureEnableBlock.setValue(newValue)
|
|
||||||
})
|
|
||||||
|
|
||||||
const toggleOnOff = () => {
|
|
||||||
isEnabled.value = !isEnabled.value
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<button @click="toggleOnOff" class="button-toggle">
|
|
||||||
<img src="/icon/128.png" class="logo" :class="{ 'logo-on': isEnabled }" alt="let me focus logo" />
|
|
||||||
</button>
|
|
||||||
<br/>
|
|
||||||
{{ isEnabled ? '[on]' : '[off]' }}
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.button-toggle {
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
border: none;
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
.button-toggle .logo {
|
|
||||||
width: 80%;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-toggle .logo-on {
|
|
||||||
filter: drop-shadow(0 0 1em #ffffff);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
15
entrypoints/content/App.tsx
Normal file
15
entrypoints/content/App.tsx
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import stopImage from "@/assets/stop.png";
|
||||||
|
import "./style.css";
|
||||||
|
import { Todo } from "@/components/Todo";
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
return (
|
||||||
|
<div class="main">
|
||||||
|
<img class="logo" src={stopImage} />
|
||||||
|
<h1 class="message">[go back to your work]</h1>
|
||||||
|
<Todo />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { ContentScriptContext } from "#imports";
|
import { ContentScriptContext } from "#imports";
|
||||||
import App from "./App.vue";
|
import App from "./App";
|
||||||
|
import { render } from "solid-js/web";
|
||||||
import { featureEnableBlock } from "@/utils/storage";
|
import { featureEnableBlock } from "@/utils/storage";
|
||||||
import { createApp } from "vue";
|
import { createProxyService } from "@webext-core/proxy-service";
|
||||||
import { createProxyService } from '@webext-core/proxy-service';
|
|
||||||
import { BlockedSite } from "@/utils/types";
|
import { BlockedSite } from "@/utils/types";
|
||||||
const blockedSitesRepo = createProxyService(BLOCKED_SITES_REPO_KEY);
|
const blockedSitesRepo = createProxyService(BLOCKED_SITES_REPO_KEY);
|
||||||
|
|
||||||
|
|
@ -14,12 +14,16 @@ export default defineContentScript({
|
||||||
const ui = await defineOverlay(ctx);
|
const ui = await defineOverlay(ctx);
|
||||||
const isBlockEnabled = await featureEnableBlock.getValue();
|
const isBlockEnabled = await featureEnableBlock.getValue();
|
||||||
const currentDomain = window.location.hostname;
|
const currentDomain = window.location.hostname;
|
||||||
const blockedSites = await blockedSitesRepo.getAll()
|
const blockedSites = await blockedSitesRepo.getAll();
|
||||||
|
|
||||||
function isOnBlockList() {
|
function isOnBlockList() {
|
||||||
return (
|
return (
|
||||||
blockedSites.filter(function (blockedSite: BlockedSite) {
|
blockedSites.filter(function (blockedSite: BlockedSite) {
|
||||||
return (blockedSite.url == currentDomain || "www." + blockedSite.url == currentDomain) && blockedSite.blocked;
|
return (
|
||||||
|
(blockedSite.url == currentDomain ||
|
||||||
|
"www." + blockedSite.url == currentDomain) &&
|
||||||
|
blockedSite.blocked
|
||||||
|
);
|
||||||
}).length > 0
|
}).length > 0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -44,8 +48,7 @@ function defineOverlay(ctx: ContentScriptContext) {
|
||||||
position: "overlay",
|
position: "overlay",
|
||||||
zIndex: 9999,
|
zIndex: 9999,
|
||||||
onMount(container, _shadow, shadowHost) {
|
onMount(container, _shadow, shadowHost) {
|
||||||
const app = createApp(App);
|
const app = render(App, container);
|
||||||
app.mount(container);
|
|
||||||
shadowHost.style.pointerEvents = "none";
|
shadowHost.style.pointerEvents = "none";
|
||||||
return app;
|
return app;
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,3 @@
|
||||||
<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 {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
@ -39,4 +25,3 @@ h1.message,
|
||||||
img.logo {
|
img.logo {
|
||||||
filter: drop-shadow(0 0 1em #ffffff);
|
filter: drop-shadow(0 0 1em #ffffff);
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
46
entrypoints/popup/App.tsx
Normal file
46
entrypoints/popup/App.tsx
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { createSignal } from "solid-js";
|
||||||
|
import "./style.css";
|
||||||
|
|
||||||
|
import { MainToggle } from "@/components/MainToggle";
|
||||||
|
import { BlockedSite } from "@/components/BlockedSite";
|
||||||
|
import { Todo } from "@/components/Todo";
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
const menus = ["main", "completed", "blocked sites"];
|
||||||
|
|
||||||
|
const [menu, setMenu] = createSignal("main");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<MainToggle />
|
||||||
|
<h1>let me focus</h1>
|
||||||
|
<ul class="menu">
|
||||||
|
<For each={menus}>
|
||||||
|
{(menu) => (
|
||||||
|
<li>
|
||||||
|
<button onClick={() => setMenu(menu)}>[{menu}]</button>
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</ul>
|
||||||
|
<Suspense>
|
||||||
|
<Switch>
|
||||||
|
<Match when={menu() === "main"}>
|
||||||
|
<Todo showInput hoverShowDeleteButton />
|
||||||
|
</Match>
|
||||||
|
<Match when={menu() === "completed"}>
|
||||||
|
<Todo showOnlyCompleted showClearAllTodo />
|
||||||
|
</Match>
|
||||||
|
<Match when={menu() === "blocked sites"}>
|
||||||
|
<BlockedSite />
|
||||||
|
</Match>
|
||||||
|
</Switch>
|
||||||
|
</Suspense>
|
||||||
|
<br />[{browser.runtime.getManifest().version}]
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
<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>
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
<meta name="manifest.type" content="browser_action" />
|
<meta name="manifest.type" content="browser_action" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="root"></div>
|
||||||
<script type="module" src="./main.ts"></script>
|
<script type="module" src="./main.tsx"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
import { createApp } from 'vue';
|
|
||||||
import './style.css';
|
|
||||||
import App from './App.vue';
|
|
||||||
|
|
||||||
createApp(App).mount('#app');
|
|
||||||
6
entrypoints/popup/main.tsx
Normal file
6
entrypoints/popup/main.tsx
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { render } from "solid-js/web";
|
||||||
|
|
||||||
|
import "./style.css";
|
||||||
|
import App from "./App";
|
||||||
|
|
||||||
|
render(() => <App />, document.getElementById("root")!);
|
||||||
|
|
@ -19,12 +19,7 @@ h1 {
|
||||||
font-size: 2.4em;
|
font-size: 2.4em;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
#root {
|
||||||
font-size: 1em;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
#app {
|
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
|
|
@ -40,3 +35,20 @@ button {
|
||||||
background-color: #f9f9f9;
|
background-color: #f9f9f9;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ul.menu {
|
||||||
|
padding: 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.menu li {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0px 5px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.menu li button {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1em;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
|
||||||
2033
package-lock.json
generated
2033
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -19,14 +19,13 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@webext-core/proxy-service": "^3.0.2",
|
"@webext-core/proxy-service": "^3.0.2",
|
||||||
"idb": "^8.0.3",
|
"idb": "^8.0.3",
|
||||||
"uuid": "^14.0.1",
|
"solid-js": "^1.9.15",
|
||||||
"vue": "^3.5.29"
|
"uuid": "^14.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@wxt-dev/module-vue": "^1.0.3",
|
"@wxt-dev/module-solid": "^1.1.4",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"vite": "^8.1.5",
|
"vite": "^8.1.5",
|
||||||
"vue-tsc": "^3.2.5",
|
|
||||||
"web-ext": "^5.5.0",
|
"web-ext": "^5.5.0",
|
||||||
"wxt": "^0.20.27"
|
"wxt": "^0.20.27"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
{
|
{
|
||||||
"extends": "./.wxt/tsconfig.json"
|
"extends": "./.wxt/tsconfig.json",
|
||||||
|
"compilerOptiosn": {
|
||||||
|
"jsx": "preserve",
|
||||||
|
"jsxImportSource": "solid-js"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { defineConfig } from 'wxt';
|
||||||
|
|
||||||
// See https://wxt.dev/api/config.html
|
// See https://wxt.dev/api/config.html
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
modules: ['@wxt-dev/module-vue'],
|
modules: ['@wxt-dev/module-solid'],
|
||||||
manifest: {
|
manifest: {
|
||||||
name: "let me focus",
|
name: "let me focus",
|
||||||
permissions: ['storage']
|
permissions: ['storage']
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue