settings catogorization
This commit is contained in:
+178
-188
@@ -1,6 +1,6 @@
|
|||||||
import { type Component, For, Show, createSignal, lazy, Suspense } from "solid-js";
|
import { type Component, For, Show, createSignal, lazy, Suspense } from "solid-js";
|
||||||
import { ThemeToggle } from "../components/ThemeToggle";
|
import { ThemeToggle } from "../components/ThemeToggle";
|
||||||
import { store, restoreTask, deleteTaskPermanently, setMatrixScaleDays, addTemplate, removeTemplate, updateTemplate, upsertTagDefinition, removeTagDefinition, renameTagDefinition, addShareRule, removeShareRule, updateShareRule, createBucket, updateBucket, deleteBucket, toggleBucketSubscription } from "@/store";
|
import { store, restoreTask, deleteTaskPermanently, addTemplate, removeTemplate, updateTemplate, upsertTagDefinition, removeTagDefinition, renameTagDefinition, addShareRule, removeShareRule, updateShareRule, createBucket, updateBucket, deleteBucket, toggleBucketSubscription } from "@/store";
|
||||||
import { useTheme } from "@/components/ThemeProvider";
|
import { useTheme } from "@/components/ThemeProvider";
|
||||||
import { Trash2, Undo2, ArrowLeftRight, Hash, Copy, Plus, ChevronDown, ChevronRight, Type, Share2, Users, Tag, Upload, Box, Edit2, Archive } from "lucide-solid";
|
import { Trash2, Undo2, ArrowLeftRight, Hash, Copy, Plus, ChevronDown, ChevronRight, Type, Share2, Users, Tag, Upload, Box, Edit2, Archive } from "lucide-solid";
|
||||||
import { TagPicker } from "@/components/TagPicker";
|
import { TagPicker } from "@/components/TagPicker";
|
||||||
@@ -62,30 +62,28 @@ export const SettingsView: Component = () => {
|
|||||||
{pb.authStore.model?.email}
|
{pb.authStore.model?.email}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex items-center gap-3 w-full sm:w-auto">
|
||||||
|
<div class="shrink-0">
|
||||||
|
<ThemeToggle />
|
||||||
|
</div>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
class="w-full sm:w-auto font-black uppercase tracking-widest text-[0.625rem] h-10 sm:h-8 rounded-xl shadow-sm border-border/60"
|
class="flex-1 sm:w-auto font-black uppercase tracking-widest text-[0.625rem] h-10 sm:h-8 rounded-xl shadow-sm border-border/60"
|
||||||
onClick={() => { pb.authStore.clear(); location.reload(); }}
|
onClick={() => { pb.authStore.clear(); location.reload(); }}
|
||||||
>
|
>
|
||||||
Sign Out
|
Sign Out
|
||||||
</Button>
|
</Button>
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="grid gap-6">
|
<div class="flex flex-col gap-12">
|
||||||
{/* Appearance */}
|
|
||||||
<section class="p-4 sm:p-5 rounded-2xl border border-border bg-card shadow-sm">
|
|
||||||
<div class="flex items-center justify-between gap-4">
|
|
||||||
<div class="space-y-0.5">
|
|
||||||
<h3 class="text-base font-semibold">Appearance</h3>
|
|
||||||
<p class="text-sm text-muted-foreground">Select your preferred color scheme.</p>
|
|
||||||
</div>
|
|
||||||
<div class="shrink-0">
|
|
||||||
<ThemeToggle />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
|
|
||||||
|
{/* Sharing Category */}
|
||||||
|
<div class="space-y-3">
|
||||||
|
<h2 class="text-xs font-bold text-muted-foreground/40 uppercase tracking-widest pl-1">Sharing</h2>
|
||||||
|
<div class="grid gap-4">
|
||||||
{/* Sharing */}
|
{/* Sharing */}
|
||||||
<section class="p-4 sm:p-5 rounded-2xl border border-border bg-card shadow-sm space-y-4 overflow-hidden">
|
<section class="p-4 sm:p-5 rounded-2xl border border-border bg-card shadow-sm space-y-4 overflow-hidden">
|
||||||
<div
|
<div
|
||||||
@@ -527,183 +525,17 @@ export const SettingsView: Component = () => {
|
|||||||
</Show>
|
</Show>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Matrix Configuration */}
|
|
||||||
<section class="p-4 sm:p-5 rounded-2xl border border-border bg-card shadow-sm space-y-4">
|
|
||||||
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
|
|
||||||
<div class="space-y-0.5 min-w-0">
|
|
||||||
<h3 class="text-base font-semibold flex items-center gap-2">
|
|
||||||
<ArrowLeftRight size={16} />
|
|
||||||
Matrix Horizon
|
|
||||||
</h3>
|
|
||||||
<p class="text-sm text-muted-foreground truncate sm:whitespace-normal">Adjust the time scale for your strategy grid.</p>
|
|
||||||
</div>
|
|
||||||
<div class="w-full sm:w-[120px] shrink-0">
|
|
||||||
<Select
|
|
||||||
value={store.matrixScaleDays.toString()}
|
|
||||||
onChange={(val) => val && setMatrixScaleDays(parseInt(val))}
|
|
||||||
options={["7", "14", "30", "60", "90"]}
|
|
||||||
placeholder="Select days"
|
|
||||||
itemComponent={(props) => <SelectItem item={props.item}>{props.item.rawValue} days</SelectItem>}
|
|
||||||
>
|
|
||||||
<SelectTrigger class="h-9 w-full">
|
|
||||||
<span class="text-sm font-medium">{store.matrixScaleDays} days</span>
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent />
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* Global Tag Manager */}
|
|
||||||
<section class="p-4 sm:p-5 rounded-2xl border border-border bg-card shadow-sm space-y-4 overflow-hidden">
|
|
||||||
<div
|
|
||||||
class="flex items-center justify-between cursor-pointer group"
|
|
||||||
onClick={() => setIsTagsOpen(!isTagsOpen())}
|
|
||||||
>
|
|
||||||
<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="w-8 h-8 rounded-full flex items-center justify-center bg-muted/50 group-hover:bg-muted transition-colors">
|
|
||||||
{isTagsOpen() ? <ChevronDown size={16} /> : <ChevronRight size={16} />}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Show when={isTagsOpen()}>
|
{/* Tasks Category */}
|
||||||
<div class="space-y-2 pt-2 animate-in fade-in slide-in-from-top-2 duration-300">
|
<div class="space-y-3">
|
||||||
<div class="space-y-2">
|
<h2 class="text-xs font-bold text-muted-foreground/40 uppercase tracking-widest pl-1">Tasks</h2>
|
||||||
<For each={store.tagDefinitions.filter(t => !t.isUser && !store.buckets.some(b => b.name === t.name)).sort((a, b) => a.name.localeCompare(b.name))} fallback={
|
<div class="grid gap-4">
|
||||||
<div class="text-center py-8 text-muted-foreground text-sm italic border border-dashed border-border rounded-xl">
|
|
||||||
No custom tags found.
|
|
||||||
</div>
|
|
||||||
}>
|
|
||||||
{(tag) => {
|
|
||||||
const [isEditingName, setIsEditingName] = createSignal(false);
|
|
||||||
const [tempName, setTempName] = createSignal(tag.name);
|
|
||||||
|
|
||||||
const handleRename = () => {
|
|
||||||
if (tempName() && tempName() !== tag.name) {
|
|
||||||
renameTagDefinition(tag.name, tempName());
|
|
||||||
}
|
|
||||||
setIsEditingName(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div class="flex flex-col sm:flex-row sm:items-center justify-between p-3 rounded-xl bg-muted/30 border border-border/50 gap-3 sm:gap-4 group">
|
|
||||||
<div class="flex items-center gap-3 min-w-0 flex-1">
|
|
||||||
<input
|
|
||||||
type="color"
|
|
||||||
value={tag.color || "#6366f1"}
|
|
||||||
onInput={(e) => upsertTagDefinition(tag.name, tag.value, e.currentTarget.value, resolvedTheme())}
|
|
||||||
class="w-4 h-4 rounded-full border-none p-0 bg-transparent cursor-pointer shrink-0 overflow-hidden"
|
|
||||||
title="Tag accent color"
|
|
||||||
/>
|
|
||||||
|
|
||||||
{isEditingName() ? (
|
|
||||||
<input
|
|
||||||
class="flex h-7 min-w-0 w-full rounded-md border border-input bg-background px-2 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
||||||
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 truncate"
|
|
||||||
onClick={() => setIsEditingName(true)}
|
|
||||||
title="Click to rename"
|
|
||||||
>
|
|
||||||
{tag.name}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center grow sm:grow-0 justify-between sm:justify-end gap-3 sm:gap-4 shrink-0 border-t sm:border-t-0 pt-2 sm:pt-0 border-border/20">
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<span class="text-[0.625rem] text-muted-foreground font-bold uppercase tracking-wider">Val</span>
|
|
||||||
<select
|
|
||||||
value={String(tag.value)}
|
|
||||||
onChange={(e) => upsertTagDefinition(tag.name, parseInt(e.currentTarget.value), tag.color, resolvedTheme())}
|
|
||||||
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 text-muted-foreground hover:text-destructive hover:bg-destructive/10"
|
|
||||||
onClick={() => {
|
|
||||||
if (confirm(`Delete tag definition for "${tag.name}" ? `)) {
|
|
||||||
removeTagDefinition(tag.name);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Trash2 size={14} />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</For>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* User/System Tags Expansion */}
|
|
||||||
<details class="group/details">
|
|
||||||
<summary class="flex items-center gap-2 text-xs font-bold uppercase tracking-wider text-muted-foreground cursor-pointer hover:text-foreground transition-colors py-2 select-none pt-4">
|
|
||||||
<div class="bg-muted/50 p-1 rounded-md group-open/details:rotate-90 transition-transform">
|
|
||||||
<ChevronRight size={12} />
|
|
||||||
</div>
|
|
||||||
System Tags (Users & Buckets)
|
|
||||||
</summary>
|
|
||||||
<div class="pt-2 pl-4 space-y-2 animate-in fade-in slide-in-from-top-1 duration-200">
|
|
||||||
<For each={store.tagDefinitions.filter(t => t.isUser || store.buckets.some(b => b.name === t.name)).sort((a, b) => a.name.localeCompare(b.name))}>
|
|
||||||
{(tag) => (
|
|
||||||
<div class="flex flex-col sm:flex-row sm:items-center justify-between p-2 rounded-lg bg-muted/10 border border-border/20 gap-3 sm:gap-4 group opacity-80">
|
|
||||||
<div class="flex items-center gap-3 min-w-0 flex-1">
|
|
||||||
<input
|
|
||||||
type="color"
|
|
||||||
value={tag.color || "#6366f1"}
|
|
||||||
onInput={(e) => upsertTagDefinition(tag.name, tag.value, e.currentTarget.value, resolvedTheme())}
|
|
||||||
class="w-4 h-4 rounded-full border-none p-0 bg-transparent cursor-pointer shrink-0 overflow-hidden"
|
|
||||||
title="Tag accent color"
|
|
||||||
/>
|
|
||||||
<span class="font-medium truncate flex items-center gap-2 text-sm">
|
|
||||||
{tag.name}
|
|
||||||
<Users size={12} class="text-muted-foreground opacity-70" />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center grow sm:grow-0 justify-between sm:justify-end gap-3 sm:gap-4 shrink-0 border-t sm:border-t-0 pt-2 sm:pt-0 border-border/20">
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<span class="text-[0.625rem] text-muted-foreground font-bold uppercase tracking-wider">Val</span>
|
|
||||||
<select
|
|
||||||
value={String(tag.value)}
|
|
||||||
onChange={(e) => upsertTagDefinition(tag.name, parseInt(e.currentTarget.value), tag.color, resolvedTheme())}
|
|
||||||
class="flex h-7 w-14 items-center justify-between rounded-md border border-input bg-background/50 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>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
</div>
|
|
||||||
</Show>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* Task Template Manager */}
|
{/* Task Template Manager */}
|
||||||
<section class="p-4 sm:p-5 rounded-2xl border border-border bg-card shadow-sm space-y-4 overflow-hidden">
|
<section class="p-4 sm:p-5 rounded-2xl border border-border bg-card shadow-sm space-y-4 overflow-hidden">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
@@ -1024,5 +856,163 @@ export const SettingsView: Component = () => {
|
|||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Organization Category */}
|
||||||
|
<div class="space-y-3">
|
||||||
|
<h2 class="text-xs font-bold text-muted-foreground/40 uppercase tracking-widest pl-1">Organization</h2>
|
||||||
|
<div class="grid gap-4">
|
||||||
|
{/* Global Tag Manager */}
|
||||||
|
<section class="p-4 sm:p-5 rounded-2xl border border-border bg-card shadow-sm space-y-4 overflow-hidden">
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between cursor-pointer group"
|
||||||
|
onClick={() => setIsTagsOpen(!isTagsOpen())}
|
||||||
|
>
|
||||||
|
<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="w-8 h-8 rounded-full flex items-center justify-center bg-muted/50 group-hover:bg-muted transition-colors">
|
||||||
|
{isTagsOpen() ? <ChevronDown size={16} /> : <ChevronRight size={16} />}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Show when={isTagsOpen()}>
|
||||||
|
<div class="space-y-2 pt-2 animate-in fade-in slide-in-from-top-2 duration-300">
|
||||||
|
<div class="space-y-2">
|
||||||
|
<For each={store.tagDefinitions.filter(t => !t.isUser && !store.buckets.some(b => b.name === t.name)).sort((a, b) => a.name.localeCompare(b.name))} fallback={
|
||||||
|
<div class="text-center py-8 text-muted-foreground text-sm italic border border-dashed border-border rounded-xl">
|
||||||
|
No custom tags found.
|
||||||
|
</div>
|
||||||
|
}>
|
||||||
|
{(tag) => {
|
||||||
|
const [isEditingName, setIsEditingName] = createSignal(false);
|
||||||
|
const [tempName, setTempName] = createSignal(tag.name);
|
||||||
|
|
||||||
|
const handleRename = () => {
|
||||||
|
if (tempName() && tempName() !== tag.name) {
|
||||||
|
renameTagDefinition(tag.name, tempName());
|
||||||
|
}
|
||||||
|
setIsEditingName(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class="flex flex-col sm:flex-row sm:items-center justify-between p-3 rounded-xl bg-muted/30 border border-border/50 gap-3 sm:gap-4 group">
|
||||||
|
<div class="flex items-center gap-3 min-w-0 flex-1">
|
||||||
|
<input
|
||||||
|
type="color"
|
||||||
|
value={tag.color || "#6366f1"}
|
||||||
|
onInput={(e) => upsertTagDefinition(tag.name, tag.value, e.currentTarget.value, resolvedTheme())}
|
||||||
|
class="w-4 h-4 rounded-full border-none p-0 bg-transparent cursor-pointer shrink-0 overflow-hidden"
|
||||||
|
title="Tag accent color"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{isEditingName() ? (
|
||||||
|
<input
|
||||||
|
class="flex h-7 min-w-0 w-full rounded-md border border-input bg-background px-2 py-1 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
||||||
|
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 truncate"
|
||||||
|
onClick={() => setIsEditingName(true)}
|
||||||
|
title="Click to rename"
|
||||||
|
>
|
||||||
|
{tag.name}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center grow sm:grow-0 justify-between sm:justify-end gap-3 sm:gap-4 shrink-0 border-t sm:border-t-0 pt-2 sm:pt-0 border-border/20">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="text-[0.625rem] text-muted-foreground font-bold uppercase tracking-wider">Val</span>
|
||||||
|
<select
|
||||||
|
value={String(tag.value)}
|
||||||
|
onChange={(e) => upsertTagDefinition(tag.name, parseInt(e.currentTarget.value), tag.color, resolvedTheme())}
|
||||||
|
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 text-muted-foreground hover:text-destructive hover:bg-destructive/10"
|
||||||
|
onClick={() => {
|
||||||
|
if (confirm(`Delete tag definition for "${tag.name}" ? `)) {
|
||||||
|
removeTagDefinition(tag.name);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Trash2 size={14} />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* User/System Tags Expansion */}
|
||||||
|
<details class="group/details">
|
||||||
|
<summary class="flex items-center gap-2 text-xs font-bold uppercase tracking-wider text-muted-foreground cursor-pointer hover:text-foreground transition-colors py-2 select-none pt-4">
|
||||||
|
<div class="bg-muted/50 p-1 rounded-md group-open/details:rotate-90 transition-transform">
|
||||||
|
<ChevronRight size={12} />
|
||||||
|
</div>
|
||||||
|
System Tags (Users & Buckets)
|
||||||
|
</summary>
|
||||||
|
<div class="pt-2 pl-4 space-y-2 animate-in fade-in slide-in-from-top-1 duration-200">
|
||||||
|
<For each={store.tagDefinitions.filter(t => t.isUser || store.buckets.some(b => b.name === t.name)).sort((a, b) => a.name.localeCompare(b.name))}>
|
||||||
|
{(tag) => (
|
||||||
|
<div class="flex flex-col sm:flex-row sm:items-center justify-between p-2 rounded-lg bg-muted/10 border border-border/20 gap-3 sm:gap-4 group opacity-80">
|
||||||
|
<div class="flex items-center gap-3 min-w-0 flex-1">
|
||||||
|
<input
|
||||||
|
type="color"
|
||||||
|
value={tag.color || "#6366f1"}
|
||||||
|
onInput={(e) => upsertTagDefinition(tag.name, tag.value, e.currentTarget.value, resolvedTheme())}
|
||||||
|
class="w-4 h-4 rounded-full border-none p-0 bg-transparent cursor-pointer shrink-0 overflow-hidden"
|
||||||
|
title="Tag accent color"
|
||||||
|
/>
|
||||||
|
<span class="font-medium truncate flex items-center gap-2 text-sm">
|
||||||
|
{tag.name}
|
||||||
|
<Users size={12} class="text-muted-foreground opacity-70" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center grow sm:grow-0 justify-between sm:justify-end gap-3 sm:gap-4 shrink-0 border-t sm:border-t-0 pt-2 sm:pt-0 border-border/20">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="text-[0.625rem] text-muted-foreground font-bold uppercase tracking-wider">Val</span>
|
||||||
|
<select
|
||||||
|
value={String(tag.value)}
|
||||||
|
onChange={(e) => upsertTagDefinition(tag.name, parseInt(e.currentTarget.value), tag.color, resolvedTheme())}
|
||||||
|
class="flex h-7 w-14 items-center justify-between rounded-md border border-input bg-background/50 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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user