diff --git a/app.vue b/app.vue index 6d6f594..9d82bd8 100644 --- a/app.vue +++ b/app.vue @@ -21,7 +21,7 @@ import "~/styles/theme.css"; import "~/styles/index.css"; import { convert } from "html-to-text"; import "iconify-icon"; -import ConfirmationModal from "./components/modals/confirmation.vue"; +import ConfirmationModal from "./components/modals/confirm.vue"; import NotificationsRenderer from "./components/notifications/notifications-renderer.vue"; import { Toaster } from "./components/ui/sonner"; import { SettingIds } from "./settings"; diff --git a/components/composer/composer.vue b/components/composer/composer.vue index ece6bc8..1fc9a1a 100644 --- a/components/composer/composer.vue +++ b/components/composer/composer.vue @@ -6,6 +6,11 @@ class="!border-none !ring-0 !outline-none rounded-none p-0 max-h-full min-h-48 !ring-offset-0" :disabled="sending" /> +
+ + +
+ @@ -65,7 +70,7 @@ - @@ -114,8 +119,10 @@ import { Button } from "../ui/button"; import { Input } from "../ui/input"; import { Textarea } from "../ui/textarea"; import { Toggle } from "../ui/toggle"; +import Files from "./files.vue"; const { Control_Enter, Command_Enter } = useMagicKeys(); +const fileInput = ref(null); watch([Control_Enter, Command_Enter], () => { if (sending.value) { @@ -141,7 +148,7 @@ const state = reactive({ files: [] as { apiId?: string; file: File; - alt: string; + alt?: string; uploading: boolean; updating: boolean; }[], @@ -191,6 +198,47 @@ const submit = async () => { } }; +const uploadFileFromEvent = (e: Event) => { + const target = e.target as HTMLInputElement; + const files = Array.from(target.files ?? []); + + uploadFiles(files); + + target.value = ""; +}; + +const uploadFiles = (files: File[]) => { + for (const file of files) { + state.files.push({ + file, + uploading: true, + updating: false, + }); + + client.value + .uploadMedia(file) + .then((media) => { + const index = state.files.findIndex((f) => f.file === file); + + if (!state.files[index]) { + return; + } + + state.files[index].apiId = media.data.id; + state.files[index].uploading = false; + }) + .catch(() => { + const index = state.files.findIndex((f) => f.file === file); + + if (!state.files[index]) { + return; + } + + state.files.splice(index, 1); + }); + } +}; + const visibilities = { public: { icon: Globe, diff --git a/components/composer/file-preview.vue b/components/composer/file-preview.vue new file mode 100644 index 0000000..a62e9c3 --- /dev/null +++ b/components/composer/file-preview.vue @@ -0,0 +1,126 @@ + + + \ No newline at end of file diff --git a/components/composer/files.vue b/components/composer/files.vue new file mode 100644 index 0000000..9aeafb1 --- /dev/null +++ b/components/composer/files.vue @@ -0,0 +1,19 @@ + + + \ No newline at end of file diff --git a/components/modals-old/composable.ts b/components/modals-old/composable.ts new file mode 100644 index 0000000..d5682fe --- /dev/null +++ b/components/modals-old/composable.ts @@ -0,0 +1,25 @@ +import { + confirmModalService, + confirmModalWithInputService, +} from "./service.ts"; +import type { ConfirmModalOptions, ConfirmModalResult } from "./types.ts"; + +export function useConfirmModal() { + const confirm = ( + options: ConfirmModalOptions, + ): Promise => { + return confirmModalService.confirm(options); + }; + + const confirmWithInput = ( + options: ConfirmModalOptions, + placeholder?: string, + ): Promise => { + return confirmModalWithInputService.confirm(options, placeholder); + }; + + return { + confirm, + confirmWithInput, + }; +} diff --git a/components/modals/confirmation.vue b/components/modals-old/confirmation.vue similarity index 100% rename from components/modals/confirmation.vue rename to components/modals-old/confirmation.vue diff --git a/components/modals/service.ts b/components/modals-old/service.ts similarity index 100% rename from components/modals/service.ts rename to components/modals-old/service.ts diff --git a/components/modals/types.ts b/components/modals-old/types.ts similarity index 100% rename from components/modals/types.ts rename to components/modals-old/types.ts diff --git a/components/modals/composable.ts b/components/modals/composable.ts index d5682fe..ab64f5e 100644 --- a/components/modals/composable.ts +++ b/components/modals/composable.ts @@ -1,25 +1,34 @@ -import { - confirmModalService, - confirmModalWithInputService, -} from "./service.ts"; -import type { ConfirmModalOptions, ConfirmModalResult } from "./types.ts"; +export type ConfirmModalOptions = { + title?: string; + message?: string; + confirmText?: string; + cancelText?: string; + inputType?: "none" | "text" | "textarea"; + defaultValue?: string; +}; -export function useConfirmModal() { - const confirm = ( - options: ConfirmModalOptions, - ): Promise => { - return confirmModalService.confirm(options); - }; +export type ConfirmModalResult = { + confirmed: boolean; + value?: string; +}; - const confirmWithInput = ( - options: ConfirmModalOptions, - placeholder?: string, - ): Promise => { - return confirmModalWithInputService.confirm(options, placeholder); - }; +class ConfirmModalService { + private modalRef = ref<{ + open: (options: ConfirmModalOptions) => Promise; + } | null>(null); - return { - confirm, - confirmWithInput, - }; + register(modal: { + open: (options: ConfirmModalOptions) => Promise; + }) { + this.modalRef.value = modal; + } + + confirm(options: ConfirmModalOptions): Promise { + if (!this.modalRef.value) { + throw new Error("Confirmation modal not initialized"); + } + return this.modalRef.value.open(options); + } } + +export const confirmModalService = new ConfirmModalService(); diff --git a/components/modals/confirm-inline.vue b/components/modals/confirm-inline.vue new file mode 100644 index 0000000..6eea9e5 --- /dev/null +++ b/components/modals/confirm-inline.vue @@ -0,0 +1,69 @@ + + +