Feature: add todo widget

This commit is contained in:
mmeau 2024-01-03 10:05:48 +01:00
parent 1c47d9d70e
commit b5a8e8aaac
6 changed files with 123 additions and 0 deletions

View File

@ -0,0 +1,13 @@
---
title: Todo
description: Todo Widget Configuration
---
The Todo widget provides a simple to-do list functionality.
It allows users to add, remove, and mark tasks as completed.
The component utilizes local storage to persist the to-do list data even when the user refreshes the page.
```yaml
widget:
type: todo
```

View File

@ -122,6 +122,7 @@ nav:
- widgets/services/syncthing-relay-server.md
- widgets/services/tailscale.md
- widgets/services/tdarr.md
- widgets/services/todo.md
- widgets/services/traefik.md
- widgets/services/transmission.md
- widgets/services/truenas.md

View File

@ -96,6 +96,7 @@ const components = {
tautulli: dynamic(() => import("./tautulli/component")),
tdarr: dynamic(() => import("./tdarr/component")),
traefik: dynamic(() => import("./traefik/component")),
todo: dynamic(() => import("./todo/component")),
transmission: dynamic(() => import("./transmission/component")),
tubearchivist: dynamic(() => import("./tubearchivist/component")),
truenas: dynamic(() => import("./truenas/component")),

View File

@ -0,0 +1,96 @@
("use client");
import { MdOutlineDelete } from "react-icons/md";
import { useEffect, useState } from "react";
import classNames from "classnames";
import Container from "components/services/widget/container";
export default function Component({ service }) {
const [todos, setTodos] = useState([]);
const [inputValue, setInputValue] = useState("");
function handleChange(e) {
setInputValue(e.target.value);
}
useEffect(() => {
const localStorageTodos = localStorage.getItem("todos");
const parsedTodos = localStorageTodos !== null ? JSON.parse(localStorageTodos) : [];
setTodos(parsedTodos);
}, []);
useEffect(() => {
if (todos.length === 0) return;
localStorage.setItem("todos", JSON.stringify(todos));
}, [todos]);
function handleSubmit(e) {
e.preventDefault();
if (inputValue.trim() === "") {
return;
}
setTodos([...todos, inputValue]);
setInputValue("");
}
const handleDelete = (index) => {
const newTodos = [...todos];
newTodos.splice(index, 1);
setTodos(newTodos);
if (newTodos.length === 0) {
localStorage.removeItem("todos");
} else {
localStorage.setItem("todos", JSON.stringify(newTodos));
}
};
return (
<Container service={service}>
<div>
{todos.map((todo, index) => (
<div key={`${todo}_${index}`} className="flex flex-row items-center">
<input type="checkbox" className="bg-theme-200/50 dark:bg-theme-900/20 rounded m-1" />
<input
className={classNames(
"bg-theme-200/50 dark:bg-theme-900/20 rounded m-1 flex-1 flex flex-col items-center justify-center text-center p-1",
inputValue === undefined ? "animate-pulse" : "",
"service-block",
)}
type="text"
value={todo}
onChange={handleChange}
disabled
/>
<button type="button" onClick={() => handleDelete(index)}>
<MdOutlineDelete />
</button>
</div>
))}
<form className="flex flex-row items-center">
<input
type="submit"
className="bg-theme-200/50 dark:bg-theme-900/20 rounded m-1 w-4 h-4 flex flex-col items-center justify-center text-center p-1 border border-[#6b7280]"
onClick={handleSubmit}
value="+"
/>
<input
className={classNames(
"bg-theme-200/50 dark:bg-theme-900/20 rounded m-1 flex-1 flex flex-col items-center justify-center text-center p-1",
inputValue === undefined ? "animate-pulse" : "",
"service-block",
)}
type="text"
value={inputValue}
onChange={handleChange}
/>
</form>
</div>
</Container>
);
}

View File

@ -0,0 +1,10 @@
const widget = {
mappings: {
"todo/latest": {
endpoint: "todo/latest",
validate: ["data"],
},
},
};
export default widget;

View File

@ -88,6 +88,7 @@ import strelaysrv from "./strelaysrv/widget";
import tailscale from "./tailscale/widget";
import tautulli from "./tautulli/widget";
import tdarr from "./tdarr/widget";
import todo from "./todo/widget";
import traefik from "./traefik/widget";
import transmission from "./transmission/widget";
import tubearchivist from "./tubearchivist/widget";
@ -193,6 +194,7 @@ const widgets = {
tailscale,
tautulli,
tdarr,
todo,
traefik,
transmission,
tubearchivist,