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>
|
||||
Loading…
Add table
Add a link
Reference in a new issue