added tags and tag manager
This commit is contained in:
@@ -1,11 +1,14 @@
|
||||
import { type Component, For } from "solid-js";
|
||||
import { ThemeToggle } from "../components/ThemeToggle";
|
||||
import { store, restoreTask, deleteTaskPermanently, setMatrixScaleDays } from "@/store";
|
||||
import { Trash2, Undo2, ArrowLeftRight } from "lucide-solid";
|
||||
import { Trash2, Undo2, ArrowLeftRight, Hash } from "lucide-solid";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { toast } from "solid-sonner";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger } from "@/components/ui/select";
|
||||
import { pb } from "@/lib/pocketbase";
|
||||
import { upsertTagDefinition, removeTagDefinition, renameTagDefinition } from "@/store";
|
||||
import { createSignal } from "solid-js";
|
||||
|
||||
export const SettingsView: Component = () => {
|
||||
return (
|
||||
@@ -56,6 +59,91 @@ export const SettingsView: Component = () => {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="p-5 rounded-2xl border border-border bg-card shadow-sm space-y-4">
|
||||
<div class="space-y-0.5">
|
||||
<h3 class="text-base font-semibold flex items-center gap-2">
|
||||
<Hash size={16} />
|
||||
Global Tags
|
||||
</h3>
|
||||
<p class="text-sm text-muted-foreground">Manage your global tag definitions and values.</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<For each={Object.entries(store.tagDefinitions || {}).sort((a, b) => a[0].localeCompare(b[0]))} fallback={
|
||||
<div class="text-center py-8 text-muted-foreground text-sm italic border border-dashed border-border rounded-xl">
|
||||
No specific tag definitions found.
|
||||
</div>
|
||||
}>
|
||||
{([tagName, val]) => {
|
||||
const [isEditingName, setIsEditingName] = createSignal(false);
|
||||
const [tempName, setTempName] = createSignal(tagName);
|
||||
|
||||
const handleRename = () => {
|
||||
if (tempName() !== tagName) {
|
||||
renameTagDefinition(tagName, tempName());
|
||||
}
|
||||
setIsEditingName(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="flex items-center justify-between p-3 rounded-xl bg-muted/30 border border-border/50">
|
||||
<div class="flex items-center gap-3 flex-1">
|
||||
<div class={cn("w-2 h-2 rounded-full shrink-0", val > 5 ? "bg-green-500" : val < 5 ? "bg-red-500" : "bg-gray-400")} />
|
||||
|
||||
{isEditingName() ? (
|
||||
<input
|
||||
class="flex h-7 w-48 rounded-md border border-input bg-background px-2 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
|
||||
value={tempName()}
|
||||
onInput={(e) => setTempName(e.currentTarget.value)}
|
||||
onBlur={handleRename}
|
||||
onKeyDown={(e) => e.key === "Enter" && handleRename()}
|
||||
autofocus
|
||||
/>
|
||||
) : (
|
||||
<span
|
||||
class="font-medium cursor-pointer hover:underline decoration-dashed underline-offset-4"
|
||||
onClick={() => setIsEditingName(true)}
|
||||
title="Click to rename"
|
||||
>
|
||||
{tagName}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-[10px] text-muted-foreground font-bold uppercase tracking-wider">Val</span>
|
||||
<select
|
||||
value={val}
|
||||
onChange={(e) => upsertTagDefinition(tagName, parseInt(e.currentTarget.value))}
|
||||
class="flex h-8 w-16 items-center justify-between rounded-md border border-input bg-background px-2 py-1 text-xs shadow-sm ring-offset-background focus:outline-none focus:ring-1 focus:ring-ring appearance-none"
|
||||
>
|
||||
<For each={["10", "9", "8", "7", "6", "5", "4", "3", "2", "1", "0"]}>
|
||||
{(v) => <option value={v}>{v}</option>}
|
||||
</For>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="h-8 w-8 hover:bg-destructive/10 hover:text-destructive"
|
||||
onClick={() => {
|
||||
if (confirm(`Delete tag "${tagName}" globally? This will remove it from all tasks.`)) {
|
||||
removeTagDefinition(tagName);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Trash2 size={14} />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</For>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="p-5 rounded-2xl border border-border bg-card shadow-sm space-y-4">
|
||||
<div class="space-y-0.5">
|
||||
<h3 class="text-base font-semibold flex items-center gap-2">
|
||||
@@ -115,6 +203,8 @@ export const SettingsView: Component = () => {
|
||||
</For>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user