-
-
{{ $t("global.create") }}
-
-
-
- -
-
-
-
-
-
+
+
+
+
+
-
- use Shift + Enter to create and add another
-
diff --git a/frontend/components/Location/Selector.vue b/frontend/components/Location/Selector.vue
index bbb4997d..bd22ebf4 100644
--- a/frontend/components/Location/Selector.vue
+++ b/frontend/components/Location/Selector.vue
@@ -1,62 +1,95 @@
-
-
-
-
- {{ cast(item.value).name }}
-
-
-
-
-
- {{ cast(item.value).treeString }}
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+ {{ $t("components.location.selector.no_location_found") }}
+
+
+
+
+
+
+ {{ location.name }}
+
+
+ {{ location.treeString }}
+
+
+
+
+
+
+
+
+
-
diff --git a/frontend/components/global/LabelMaker.vue b/frontend/components/global/LabelMaker.vue
index 8e29b6dc..bc40c3dd 100644
--- a/frontend/components/global/LabelMaker.vue
+++ b/frontend/components/global/LabelMaker.vue
@@ -1,5 +1,6 @@
diff --git a/frontend/components/global/QuickMenu/Modal.vue b/frontend/components/global/QuickMenu/Modal.vue
deleted file mode 100644
index 84eb8838..00000000
--- a/frontend/components/global/QuickMenu/Modal.vue
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
- {{ $t("components.quick_menu.shortcut_hint") }}
-
-
-
-
-
-
diff --git a/frontend/components/ui/alert-dialog/AlertDialog.vue b/frontend/components/ui/alert-dialog/AlertDialog.vue
new file mode 100644
index 00000000..035b4881
--- /dev/null
+++ b/frontend/components/ui/alert-dialog/AlertDialog.vue
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/alert-dialog/AlertDialogAction.vue b/frontend/components/ui/alert-dialog/AlertDialogAction.vue
new file mode 100644
index 00000000..722c4fcf
--- /dev/null
+++ b/frontend/components/ui/alert-dialog/AlertDialogAction.vue
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/alert-dialog/AlertDialogCancel.vue b/frontend/components/ui/alert-dialog/AlertDialogCancel.vue
new file mode 100644
index 00000000..7ec5b6b2
--- /dev/null
+++ b/frontend/components/ui/alert-dialog/AlertDialogCancel.vue
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/alert-dialog/AlertDialogContent.vue b/frontend/components/ui/alert-dialog/AlertDialogContent.vue
new file mode 100644
index 00000000..30ff8f45
--- /dev/null
+++ b/frontend/components/ui/alert-dialog/AlertDialogContent.vue
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/alert-dialog/AlertDialogDescription.vue b/frontend/components/ui/alert-dialog/AlertDialogDescription.vue
new file mode 100644
index 00000000..4577a4d0
--- /dev/null
+++ b/frontend/components/ui/alert-dialog/AlertDialogDescription.vue
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/alert-dialog/AlertDialogFooter.vue b/frontend/components/ui/alert-dialog/AlertDialogFooter.vue
new file mode 100644
index 00000000..55d0a0eb
--- /dev/null
+++ b/frontend/components/ui/alert-dialog/AlertDialogFooter.vue
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/alert-dialog/AlertDialogHeader.vue b/frontend/components/ui/alert-dialog/AlertDialogHeader.vue
new file mode 100644
index 00000000..c61c4495
--- /dev/null
+++ b/frontend/components/ui/alert-dialog/AlertDialogHeader.vue
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/alert-dialog/AlertDialogTitle.vue b/frontend/components/ui/alert-dialog/AlertDialogTitle.vue
new file mode 100644
index 00000000..fd17cd52
--- /dev/null
+++ b/frontend/components/ui/alert-dialog/AlertDialogTitle.vue
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/alert-dialog/AlertDialogTrigger.vue b/frontend/components/ui/alert-dialog/AlertDialogTrigger.vue
new file mode 100644
index 00000000..aabd777e
--- /dev/null
+++ b/frontend/components/ui/alert-dialog/AlertDialogTrigger.vue
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/alert-dialog/index.ts b/frontend/components/ui/alert-dialog/index.ts
new file mode 100644
index 00000000..448d5198
--- /dev/null
+++ b/frontend/components/ui/alert-dialog/index.ts
@@ -0,0 +1,9 @@
+export { default as AlertDialog } from './AlertDialog.vue'
+export { default as AlertDialogAction } from './AlertDialogAction.vue'
+export { default as AlertDialogCancel } from './AlertDialogCancel.vue'
+export { default as AlertDialogContent } from './AlertDialogContent.vue'
+export { default as AlertDialogDescription } from './AlertDialogDescription.vue'
+export { default as AlertDialogFooter } from './AlertDialogFooter.vue'
+export { default as AlertDialogHeader } from './AlertDialogHeader.vue'
+export { default as AlertDialogTitle } from './AlertDialogTitle.vue'
+export { default as AlertDialogTrigger } from './AlertDialogTrigger.vue'
diff --git a/frontend/components/ui/badge/Badge.vue b/frontend/components/ui/badge/Badge.vue
new file mode 100644
index 00000000..9ed80393
--- /dev/null
+++ b/frontend/components/ui/badge/Badge.vue
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/badge/index.ts b/frontend/components/ui/badge/index.ts
new file mode 100644
index 00000000..35e7a1a0
--- /dev/null
+++ b/frontend/components/ui/badge/index.ts
@@ -0,0 +1,25 @@
+import { cva, type VariantProps } from 'class-variance-authority'
+
+export { default as Badge } from './Badge.vue'
+
+export const badgeVariants = cva(
+ 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
+ {
+ variants: {
+ variant: {
+ default:
+ 'border-transparent bg-primary text-primary-foreground hover:bg-primary/80',
+ secondary:
+ 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
+ destructive:
+ 'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80',
+ outline: 'text-foreground',
+ },
+ },
+ defaultVariants: {
+ variant: 'default',
+ },
+ },
+)
+
+export type BadgeVariants = VariantProps
diff --git a/frontend/components/ui/button/Button.vue b/frontend/components/ui/button/Button.vue
index 19c44c15..b330368b 100644
--- a/frontend/components/ui/button/Button.vue
+++ b/frontend/components/ui/button/Button.vue
@@ -1,6 +1,6 @@
+
+
+
+
+
+
diff --git a/frontend/components/ui/button/index.ts b/frontend/components/ui/button/index.ts
index 417aeb03..14ee433e 100644
--- a/frontend/components/ui/button/index.ts
+++ b/frontend/components/ui/button/index.ts
@@ -1,6 +1,7 @@
import { cva, type VariantProps } from "class-variance-authority";
export { default as Button } from "./Button.vue";
+export { default as ButtonGroup } from "./ButtonGroup.vue";
export const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
diff --git a/frontend/components/ui/command/Command.vue b/frontend/components/ui/command/Command.vue
new file mode 100644
index 00000000..467ae019
--- /dev/null
+++ b/frontend/components/ui/command/Command.vue
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/command/CommandDialog.vue b/frontend/components/ui/command/CommandDialog.vue
new file mode 100644
index 00000000..825774ec
--- /dev/null
+++ b/frontend/components/ui/command/CommandDialog.vue
@@ -0,0 +1,21 @@
+
+
+
+
+
diff --git a/frontend/components/ui/command/CommandEmpty.vue b/frontend/components/ui/command/CommandEmpty.vue
new file mode 100644
index 00000000..1908f93c
--- /dev/null
+++ b/frontend/components/ui/command/CommandEmpty.vue
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/command/CommandGroup.vue b/frontend/components/ui/command/CommandGroup.vue
new file mode 100644
index 00000000..683bf592
--- /dev/null
+++ b/frontend/components/ui/command/CommandGroup.vue
@@ -0,0 +1,29 @@
+
+
+
+
+
+ {{ heading }}
+
+
+
+
diff --git a/frontend/components/ui/command/CommandInput.vue b/frontend/components/ui/command/CommandInput.vue
new file mode 100644
index 00000000..2713203f
--- /dev/null
+++ b/frontend/components/ui/command/CommandInput.vue
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/command/CommandItem.vue b/frontend/components/ui/command/CommandItem.vue
new file mode 100644
index 00000000..dd5a872d
--- /dev/null
+++ b/frontend/components/ui/command/CommandItem.vue
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/command/CommandList.vue b/frontend/components/ui/command/CommandList.vue
new file mode 100644
index 00000000..9106b444
--- /dev/null
+++ b/frontend/components/ui/command/CommandList.vue
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/command/CommandSeparator.vue b/frontend/components/ui/command/CommandSeparator.vue
new file mode 100644
index 00000000..cc5f0550
--- /dev/null
+++ b/frontend/components/ui/command/CommandSeparator.vue
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/command/CommandShortcut.vue b/frontend/components/ui/command/CommandShortcut.vue
new file mode 100644
index 00000000..0d4da921
--- /dev/null
+++ b/frontend/components/ui/command/CommandShortcut.vue
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/command/index.ts b/frontend/components/ui/command/index.ts
new file mode 100644
index 00000000..0e35f4b9
--- /dev/null
+++ b/frontend/components/ui/command/index.ts
@@ -0,0 +1,9 @@
+export { default as Command } from './Command.vue'
+export { default as CommandDialog } from './CommandDialog.vue'
+export { default as CommandEmpty } from './CommandEmpty.vue'
+export { default as CommandGroup } from './CommandGroup.vue'
+export { default as CommandInput } from './CommandInput.vue'
+export { default as CommandItem } from './CommandItem.vue'
+export { default as CommandList } from './CommandList.vue'
+export { default as CommandSeparator } from './CommandSeparator.vue'
+export { default as CommandShortcut } from './CommandShortcut.vue'
diff --git a/frontend/components/ui/dialog-provider/DialogProvider.vue b/frontend/components/ui/dialog-provider/DialogProvider.vue
new file mode 100644
index 00000000..c7513012
--- /dev/null
+++ b/frontend/components/ui/dialog-provider/DialogProvider.vue
@@ -0,0 +1,48 @@
+
+
+
+
+
+
diff --git a/frontend/components/ui/dialog-provider/index.ts b/frontend/components/ui/dialog-provider/index.ts
new file mode 100644
index 00000000..cc9f4adb
--- /dev/null
+++ b/frontend/components/ui/dialog-provider/index.ts
@@ -0,0 +1,2 @@
+export { useDialog, useDialogHotkey } from "./utils";
+export { default as DialogProvider } from "./DialogProvider.vue";
diff --git a/frontend/components/ui/dialog-provider/utils.ts b/frontend/components/ui/dialog-provider/utils.ts
new file mode 100644
index 00000000..3309ddb2
--- /dev/null
+++ b/frontend/components/ui/dialog-provider/utils.ts
@@ -0,0 +1,56 @@
+import type { ComputedRef } from "vue";
+import { createContext } from "reka-ui";
+import { useMagicKeys, useActiveElement } from "@vueuse/core";
+
+export const [useDialog, provideDialogContext] = createContext<{
+ activeDialog: ComputedRef;
+ activeAlerts: ComputedRef;
+ openDialog: (dialogId: string) => void;
+ closeDialog: (dialogId?: string) => void;
+ addAlert: (alertId: string) => void;
+ removeAlert: (alertId: string) => void;
+}>("DialogProvider");
+
+export const useDialogHotkey = (
+ dialogId: string,
+ key: {
+ shift?: boolean;
+ ctrl?: boolean;
+ code: string;
+ }
+) => {
+ const { openDialog } = useDialog();
+
+ const activeElement = useActiveElement();
+
+ const notUsingInput = computed(
+ () => activeElement.value?.tagName !== "INPUT" && activeElement.value?.tagName !== "TEXTAREA"
+ );
+
+ useMagicKeys({
+ passive: false,
+ onEventFired: event => {
+ // console.log({
+ // event,
+ // notUsingInput: notUsingInput.value,
+ // eventType: event.type,
+ // keyCode: event.code,
+ // matchingKeyCode: key.code === event.code,
+ // shift: event.shiftKey,
+ // matchingShift: key.shift === undefined || event.shiftKey === key.shift,
+ // ctrl: event.ctrlKey,
+ // matchingCtrl: key.ctrl === undefined || event.ctrlKey === key.ctrl,
+ // });
+ if (
+ notUsingInput.value &&
+ event.type === "keydown" &&
+ event.code === key.code &&
+ (key.shift === undefined || event.shiftKey === key.shift) &&
+ (key.ctrl === undefined || event.ctrlKey === key.ctrl)
+ ) {
+ openDialog(dialogId);
+ event.preventDefault();
+ }
+ },
+ });
+};
diff --git a/frontend/components/ui/dialog/Dialog.vue b/frontend/components/ui/dialog/Dialog.vue
new file mode 100644
index 00000000..a174bd05
--- /dev/null
+++ b/frontend/components/ui/dialog/Dialog.vue
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/dialog/DialogClose.vue b/frontend/components/ui/dialog/DialogClose.vue
new file mode 100644
index 00000000..ba036b51
--- /dev/null
+++ b/frontend/components/ui/dialog/DialogClose.vue
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/dialog/DialogContent.vue b/frontend/components/ui/dialog/DialogContent.vue
new file mode 100644
index 00000000..be00c5e6
--- /dev/null
+++ b/frontend/components/ui/dialog/DialogContent.vue
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+ Close
+
+
+
+
diff --git a/frontend/components/ui/dialog/DialogDescription.vue b/frontend/components/ui/dialog/DialogDescription.vue
new file mode 100644
index 00000000..5afbab04
--- /dev/null
+++ b/frontend/components/ui/dialog/DialogDescription.vue
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/dialog/DialogFooter.vue b/frontend/components/ui/dialog/DialogFooter.vue
new file mode 100644
index 00000000..ac2d0c18
--- /dev/null
+++ b/frontend/components/ui/dialog/DialogFooter.vue
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/dialog/DialogHeader.vue b/frontend/components/ui/dialog/DialogHeader.vue
new file mode 100644
index 00000000..b2c9085d
--- /dev/null
+++ b/frontend/components/ui/dialog/DialogHeader.vue
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/dialog/DialogScrollContent.vue b/frontend/components/ui/dialog/DialogScrollContent.vue
new file mode 100644
index 00000000..c1caf2be
--- /dev/null
+++ b/frontend/components/ui/dialog/DialogScrollContent.vue
@@ -0,0 +1,59 @@
+
+
+
+
+
+ ) => {
+ const originalEvent = event.detail.originalEvent;
+ const target = originalEvent.target as HTMLElement;
+ if (originalEvent.offsetX > target.clientWidth || originalEvent.offsetY > target.clientHeight) {
+ event.preventDefault();
+ }
+ }"
+ >
+
+
+
+
+ Close
+
+
+
+
+
diff --git a/frontend/components/ui/dialog/DialogTitle.vue b/frontend/components/ui/dialog/DialogTitle.vue
new file mode 100644
index 00000000..30cbb368
--- /dev/null
+++ b/frontend/components/ui/dialog/DialogTitle.vue
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/dialog/DialogTrigger.vue b/frontend/components/ui/dialog/DialogTrigger.vue
new file mode 100644
index 00000000..2984f371
--- /dev/null
+++ b/frontend/components/ui/dialog/DialogTrigger.vue
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/dialog/index.ts b/frontend/components/ui/dialog/index.ts
new file mode 100644
index 00000000..ca8cfeae
--- /dev/null
+++ b/frontend/components/ui/dialog/index.ts
@@ -0,0 +1,9 @@
+export { default as Dialog } from './Dialog.vue'
+export { default as DialogClose } from './DialogClose.vue'
+export { default as DialogContent } from './DialogContent.vue'
+export { default as DialogDescription } from './DialogDescription.vue'
+export { default as DialogFooter } from './DialogFooter.vue'
+export { default as DialogHeader } from './DialogHeader.vue'
+export { default as DialogScrollContent } from './DialogScrollContent.vue'
+export { default as DialogTitle } from './DialogTitle.vue'
+export { default as DialogTrigger } from './DialogTrigger.vue'
diff --git a/frontend/components/ui/drawer/Drawer.vue b/frontend/components/ui/drawer/Drawer.vue
new file mode 100644
index 00000000..a30a01e6
--- /dev/null
+++ b/frontend/components/ui/drawer/Drawer.vue
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/drawer/DrawerContent.vue b/frontend/components/ui/drawer/DrawerContent.vue
new file mode 100644
index 00000000..618df111
--- /dev/null
+++ b/frontend/components/ui/drawer/DrawerContent.vue
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/drawer/DrawerDescription.vue b/frontend/components/ui/drawer/DrawerDescription.vue
new file mode 100644
index 00000000..092dc503
--- /dev/null
+++ b/frontend/components/ui/drawer/DrawerDescription.vue
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/drawer/DrawerFooter.vue b/frontend/components/ui/drawer/DrawerFooter.vue
new file mode 100644
index 00000000..1eb35278
--- /dev/null
+++ b/frontend/components/ui/drawer/DrawerFooter.vue
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/drawer/DrawerHeader.vue b/frontend/components/ui/drawer/DrawerHeader.vue
new file mode 100644
index 00000000..ecef7a67
--- /dev/null
+++ b/frontend/components/ui/drawer/DrawerHeader.vue
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/drawer/DrawerOverlay.vue b/frontend/components/ui/drawer/DrawerOverlay.vue
new file mode 100644
index 00000000..f9307b71
--- /dev/null
+++ b/frontend/components/ui/drawer/DrawerOverlay.vue
@@ -0,0 +1,18 @@
+
+
+
+
+
diff --git a/frontend/components/ui/drawer/DrawerTitle.vue b/frontend/components/ui/drawer/DrawerTitle.vue
new file mode 100644
index 00000000..475c3ab4
--- /dev/null
+++ b/frontend/components/ui/drawer/DrawerTitle.vue
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/drawer/index.ts b/frontend/components/ui/drawer/index.ts
new file mode 100644
index 00000000..d41b7928
--- /dev/null
+++ b/frontend/components/ui/drawer/index.ts
@@ -0,0 +1,8 @@
+export { default as Drawer } from './Drawer.vue'
+export { default as DrawerContent } from './DrawerContent.vue'
+export { default as DrawerDescription } from './DrawerDescription.vue'
+export { default as DrawerFooter } from './DrawerFooter.vue'
+export { default as DrawerHeader } from './DrawerHeader.vue'
+export { default as DrawerOverlay } from './DrawerOverlay.vue'
+export { default as DrawerTitle } from './DrawerTitle.vue'
+export { DrawerClose, DrawerPortal, DrawerTrigger } from 'vaul-vue'
diff --git a/frontend/components/ui/dropdown-menu/DropdownMenu.vue b/frontend/components/ui/dropdown-menu/DropdownMenu.vue
index 3e142aaf..f9adc74b 100644
--- a/frontend/components/ui/dropdown-menu/DropdownMenu.vue
+++ b/frontend/components/ui/dropdown-menu/DropdownMenu.vue
@@ -4,7 +4,7 @@
type DropdownMenuRootEmits,
type DropdownMenuRootProps,
useForwardPropsEmits,
- } from "radix-vue";
+ } from "reka-ui";
const props = defineProps();
const emits = defineEmits();
diff --git a/frontend/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue b/frontend/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue
index d992ec1f..dad68f98 100644
--- a/frontend/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue
+++ b/frontend/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue
@@ -6,7 +6,7 @@
type DropdownMenuCheckboxItemProps,
DropdownMenuItemIndicator,
useForwardPropsEmits,
- } from "radix-vue";
+ } from "reka-ui";
import { computed, type HTMLAttributes } from "vue";
import { cn } from "@/lib/utils";
diff --git a/frontend/components/ui/dropdown-menu/DropdownMenuContent.vue b/frontend/components/ui/dropdown-menu/DropdownMenuContent.vue
index d7006d0e..c99785c9 100644
--- a/frontend/components/ui/dropdown-menu/DropdownMenuContent.vue
+++ b/frontend/components/ui/dropdown-menu/DropdownMenuContent.vue
@@ -5,7 +5,7 @@
type DropdownMenuContentProps,
DropdownMenuPortal,
useForwardPropsEmits,
- } from "radix-vue";
+ } from "reka-ui";
import { computed, type HTMLAttributes } from "vue";
import { cn } from "@/lib/utils";
diff --git a/frontend/components/ui/dropdown-menu/DropdownMenuGroup.vue b/frontend/components/ui/dropdown-menu/DropdownMenuGroup.vue
index 84f14944..7c1f0df3 100644
--- a/frontend/components/ui/dropdown-menu/DropdownMenuGroup.vue
+++ b/frontend/components/ui/dropdown-menu/DropdownMenuGroup.vue
@@ -1,5 +1,5 @@
diff --git a/frontend/components/ui/dropdown-menu/DropdownMenuItem.vue b/frontend/components/ui/dropdown-menu/DropdownMenuItem.vue
index 20d29de9..28c60bc4 100644
--- a/frontend/components/ui/dropdown-menu/DropdownMenuItem.vue
+++ b/frontend/components/ui/dropdown-menu/DropdownMenuItem.vue
@@ -1,5 +1,5 @@
+
+
+
+
diff --git a/frontend/components/ui/label/index.ts b/frontend/components/ui/label/index.ts
new file mode 100644
index 00000000..572c2f01
--- /dev/null
+++ b/frontend/components/ui/label/index.ts
@@ -0,0 +1 @@
+export { default as Label } from './Label.vue'
diff --git a/frontend/components/ui/popover/Popover.vue b/frontend/components/ui/popover/Popover.vue
new file mode 100644
index 00000000..72e0b5fa
--- /dev/null
+++ b/frontend/components/ui/popover/Popover.vue
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/popover/PopoverContent.vue b/frontend/components/ui/popover/PopoverContent.vue
new file mode 100644
index 00000000..9e6c2882
--- /dev/null
+++ b/frontend/components/ui/popover/PopoverContent.vue
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/popover/PopoverTrigger.vue b/frontend/components/ui/popover/PopoverTrigger.vue
new file mode 100644
index 00000000..ac265950
--- /dev/null
+++ b/frontend/components/ui/popover/PopoverTrigger.vue
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/popover/index.ts b/frontend/components/ui/popover/index.ts
new file mode 100644
index 00000000..c621f9b1
--- /dev/null
+++ b/frontend/components/ui/popover/index.ts
@@ -0,0 +1,3 @@
+export { default as Popover } from './Popover.vue'
+export { default as PopoverContent } from './PopoverContent.vue'
+export { default as PopoverTrigger } from './PopoverTrigger.vue'
diff --git a/frontend/components/ui/separator/Separator.vue b/frontend/components/ui/separator/Separator.vue
index 62fd094e..0fc01413 100644
--- a/frontend/components/ui/separator/Separator.vue
+++ b/frontend/components/ui/separator/Separator.vue
@@ -1,5 +1,5 @@
diff --git a/frontend/components/ui/sheet/SheetContent.vue b/frontend/components/ui/sheet/SheetContent.vue
index 74314684..5ee4992b 100644
--- a/frontend/components/ui/sheet/SheetContent.vue
+++ b/frontend/components/ui/sheet/SheetContent.vue
@@ -8,7 +8,7 @@
DialogOverlay,
DialogPortal,
useForwardPropsEmits,
- } from "radix-vue";
+ } from "reka-ui";
import { computed, type HTMLAttributes } from "vue";
import { type SheetVariants, sheetVariants } from ".";
import { cn } from "@/lib/utils";
@@ -38,7 +38,7 @@
diff --git a/frontend/components/ui/sheet/SheetDescription.vue b/frontend/components/ui/sheet/SheetDescription.vue
index f60bc6a4..9e86a3e5 100644
--- a/frontend/components/ui/sheet/SheetDescription.vue
+++ b/frontend/components/ui/sheet/SheetDescription.vue
@@ -1,5 +1,5 @@
diff --git a/frontend/components/ui/shortcut/Shortcut.vue b/frontend/components/ui/shortcut/Shortcut.vue
new file mode 100644
index 00000000..3087da13
--- /dev/null
+++ b/frontend/components/ui/shortcut/Shortcut.vue
@@ -0,0 +1,35 @@
+
+
+
+
+
+ {{ key }}
+
+
+
diff --git a/frontend/components/ui/shortcut/index.ts b/frontend/components/ui/shortcut/index.ts
new file mode 100644
index 00000000..f2557e1e
--- /dev/null
+++ b/frontend/components/ui/shortcut/index.ts
@@ -0,0 +1 @@
+export { default as Shortcut } from './Shortcut.vue'
diff --git a/frontend/components/ui/sidebar/Sidebar.vue b/frontend/components/ui/sidebar/Sidebar.vue
index 91a237d1..a35d170e 100644
--- a/frontend/components/ui/sidebar/Sidebar.vue
+++ b/frontend/components/ui/sidebar/Sidebar.vue
@@ -31,7 +31,7 @@
data-sidebar="sidebar"
data-mobile="true"
:side="side"
- class="bg-sidebar text-sidebar-foreground w-[--sidebar-width] p-0 [&>button]:hidden"
+ class="bg-sidebar text-sidebar-foreground z-40 w-[--sidebar-width] p-0 [&>button]:hidden"
:style="{
'--sidebar-width': SIDEBAR_WIDTH_MOBILE,
}"
diff --git a/frontend/components/ui/sidebar/SidebarGroupAction.vue b/frontend/components/ui/sidebar/SidebarGroupAction.vue
index 419ee1ad..29ce1a7f 100644
--- a/frontend/components/ui/sidebar/SidebarGroupAction.vue
+++ b/frontend/components/ui/sidebar/SidebarGroupAction.vue
@@ -1,7 +1,7 @@
+
+
+
+
+
diff --git a/frontend/components/ui/sonner/index.ts b/frontend/components/ui/sonner/index.ts
new file mode 100644
index 00000000..98dd0bbe
--- /dev/null
+++ b/frontend/components/ui/sonner/index.ts
@@ -0,0 +1,2 @@
+export { default as Toaster } from './Sonner.vue'
+export { toast } from './toast'
\ No newline at end of file
diff --git a/frontend/components/ui/sonner/toast.ts b/frontend/components/ui/sonner/toast.ts
new file mode 100644
index 00000000..7a965dcf
--- /dev/null
+++ b/frontend/components/ui/sonner/toast.ts
@@ -0,0 +1,20 @@
+import { toast as internalToast } from "vue-sonner";
+
+// triggering too many toasts at once can cause the toaster to not render properly https://github.com/xiaoluoboding/vue-sonner/issues/98
+
+const wrapToast = any>(fn: T): ((...args: Parameters) => Promise>) => {
+ return (...args: Parameters) =>
+ new Promise(resolve => {
+ setTimeout(() => resolve(fn(...args)), 0);
+ });
+};
+
+const toast = (...args: Parameters) => internalToast(...args);
+
+toast.success = wrapToast(internalToast.success);
+toast.info = wrapToast(internalToast.info);
+toast.warning = wrapToast(internalToast.warning);
+toast.error = wrapToast(internalToast.error);
+toast.message = wrapToast(internalToast.message);
+
+export { toast };
diff --git a/frontend/components/ui/tags-input/TagsInput.vue b/frontend/components/ui/tags-input/TagsInput.vue
new file mode 100644
index 00000000..879e6a1d
--- /dev/null
+++ b/frontend/components/ui/tags-input/TagsInput.vue
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/tags-input/TagsInputInput.vue b/frontend/components/ui/tags-input/TagsInputInput.vue
new file mode 100644
index 00000000..66841ffc
--- /dev/null
+++ b/frontend/components/ui/tags-input/TagsInputInput.vue
@@ -0,0 +1,19 @@
+
+
+
+
+
diff --git a/frontend/components/ui/tags-input/TagsInputItem.vue b/frontend/components/ui/tags-input/TagsInputItem.vue
new file mode 100644
index 00000000..06656575
--- /dev/null
+++ b/frontend/components/ui/tags-input/TagsInputItem.vue
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/tags-input/TagsInputItemDelete.vue b/frontend/components/ui/tags-input/TagsInputItemDelete.vue
new file mode 100644
index 00000000..be8aa4d3
--- /dev/null
+++ b/frontend/components/ui/tags-input/TagsInputItemDelete.vue
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/tags-input/TagsInputItemText.vue b/frontend/components/ui/tags-input/TagsInputItemText.vue
new file mode 100644
index 00000000..7814df88
--- /dev/null
+++ b/frontend/components/ui/tags-input/TagsInputItemText.vue
@@ -0,0 +1,19 @@
+
+
+
+
+
diff --git a/frontend/components/ui/tags-input/index.ts b/frontend/components/ui/tags-input/index.ts
new file mode 100644
index 00000000..31305f34
--- /dev/null
+++ b/frontend/components/ui/tags-input/index.ts
@@ -0,0 +1,5 @@
+export { default as TagsInput } from './TagsInput.vue'
+export { default as TagsInputInput } from './TagsInputInput.vue'
+export { default as TagsInputItem } from './TagsInputItem.vue'
+export { default as TagsInputItemDelete } from './TagsInputItemDelete.vue'
+export { default as TagsInputItemText } from './TagsInputItemText.vue'
diff --git a/frontend/components/ui/textarea/Textarea.vue b/frontend/components/ui/textarea/Textarea.vue
new file mode 100644
index 00000000..e4a7c139
--- /dev/null
+++ b/frontend/components/ui/textarea/Textarea.vue
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
diff --git a/frontend/components/ui/textarea/index.ts b/frontend/components/ui/textarea/index.ts
new file mode 100644
index 00000000..6a7ab2a7
--- /dev/null
+++ b/frontend/components/ui/textarea/index.ts
@@ -0,0 +1 @@
+export { default as Textarea } from './Textarea.vue'
diff --git a/frontend/components/ui/tooltip/Tooltip.vue b/frontend/components/ui/tooltip/Tooltip.vue
index 319c04a7..6c219b78 100644
--- a/frontend/components/ui/tooltip/Tooltip.vue
+++ b/frontend/components/ui/tooltip/Tooltip.vue
@@ -1,5 +1,5 @@
diff --git a/frontend/components/ui/tooltip/TooltipTrigger.vue b/frontend/components/ui/tooltip/TooltipTrigger.vue
index 21ba4ed9..8b7edcba 100644
--- a/frontend/components/ui/tooltip/TooltipTrigger.vue
+++ b/frontend/components/ui/tooltip/TooltipTrigger.vue
@@ -1,5 +1,5 @@
diff --git a/frontend/composables/use-ids.ts b/frontend/composables/use-ids.ts
deleted file mode 100755
index 98b896a8..00000000
--- a/frontend/composables/use-ids.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-function slugify(text: string) {
- return text
- .toString()
- .toLowerCase()
- .replace(/\s+/g, "-") // Replace spaces with -
- .replace(/[^\w-]+/g, "") // Remove all non-word chars
- .replace(/--+/g, "-") // Replace multiple - with single -
- .replace(/^-+/, "") // Trim - from start of text
- .replace(/-+$/, ""); // Trim - from end of text
-}
-
-function idGenerator(): string {
- const id = Math.random().toString(32).substring(2, 6) + Math.random().toString(36).substring(2, 6);
- return slugify(id);
-}
-
-/**
- * useFormIds uses the provided label to generate a unique id for the
- * form element. If no label is provided the id is generated using a
- * random string.
- */
-export function useFormIds(label: string): string {
- const slug = label ? slugify(label) : idGenerator();
- return `${slug}-${idGenerator()}`;
-}
-
-export function useId(): string {
- return idGenerator();
-}
diff --git a/frontend/composables/use-notifier.ts b/frontend/composables/use-notifier.ts
deleted file mode 100644
index 37243dac..00000000
--- a/frontend/composables/use-notifier.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import { useId } from "./use-ids";
-
-interface Notification {
- id: string;
- message: string;
- type: "success" | "error" | "info";
-}
-
-const notifications = ref([]);
-
-function addNotification(notification: Notification) {
- notifications.value.unshift(notification);
-
- if (notifications.value.length > 4) {
- notifications.value.pop();
- } else {
- setTimeout(() => {
- // Remove notification with ID
- notifications.value = notifications.value.filter(n => n.id !== notification.id);
- }, 5000);
- }
-}
-
-export function useNotifications() {
- return {
- notifications,
- dropNotification: (idx: number) => notifications.value.splice(idx, 1),
- };
-}
-
-export function useNotifier() {
- return {
- success: (message: string) => {
- addNotification({
- id: useId(),
- message,
- type: "success",
- });
- },
- error: (message: string) => {
- addNotification({
- id: useId(),
- message,
- type: "error",
- });
- },
- info: (message: string) => {
- addNotification({
- id: useId(),
- message,
- type: "info",
- });
- },
- };
-}
diff --git a/frontend/layouts/default.vue b/frontend/layouts/default.vue
index 8f452d37..5fcf4899 100644
--- a/frontend/layouts/default.vue
+++ b/frontend/layouts/default.vue
@@ -4,15 +4,14 @@
Confirmation Modal is a singleton used by all components so we render
it here to ensure it's always available. Possibly could move this further
up the tree
- -->
+ -->
-
-
-
-
-
-
-
+
+
+
+
+
+
{{ $t("global.welcome", { username: username }) }}
@@ -34,17 +33,19 @@
-