2024-04-27 09:04:02 +02:00
|
|
|
<template>
|
2024-12-01 18:29:54 +01:00
|
|
|
<div v-if="relation" class="rounded border overflow-auto max-h-72">
|
|
|
|
|
<Note :note="relation.note" :hide-actions="true" :small-layout="true" />
|
|
|
|
|
</div>
|
|
|
|
|
|
2025-03-27 22:20:04 +01:00
|
|
|
<Input
|
|
|
|
|
v-model:model-value="state.contentWarning"
|
|
|
|
|
v-if="state.sensitive"
|
|
|
|
|
placeholder="Put your content warning here"
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<EditorContent
|
|
|
|
|
v-model:content="state.content"
|
|
|
|
|
:placeholder="chosenSplash"
|
2024-12-26 13:44:52 +01:00
|
|
|
class="*:!border-none *:!ring-0 *:!outline-none *:rounded-none p-0 *:max-h-[50dvh] *:overflow-y-auto *:min-h-48 *:!ring-offset-0 *:h-full"
|
2025-03-27 22:20:04 +01:00
|
|
|
:disabled="sending"
|
|
|
|
|
:mode="state.contentType === 'text/html' ? 'rich' : 'plain'"
|
|
|
|
|
/>
|
2024-12-01 15:30:42 +01:00
|
|
|
|
2024-12-01 17:20:21 +01:00
|
|
|
<div class="w-full flex flex-row gap-2 overflow-x-auto *:shrink-0 pb-2">
|
2025-03-27 22:20:04 +01:00
|
|
|
<input
|
|
|
|
|
type="file"
|
|
|
|
|
ref="fileInput"
|
|
|
|
|
@change="uploadFileFromEvent"
|
|
|
|
|
class="hidden"
|
|
|
|
|
multiple
|
|
|
|
|
/>
|
2024-12-01 17:20:21 +01:00
|
|
|
<Files v-model:files="state.files" />
|
|
|
|
|
</div>
|
|
|
|
|
|
2024-12-01 15:30:42 +01:00
|
|
|
<DialogFooter class="items-center flex-row">
|
2024-12-02 12:33:53 +01:00
|
|
|
<Tooltip>
|
|
|
|
|
<TooltipTrigger as="div">
|
|
|
|
|
<Button variant="ghost" size="icon">
|
|
|
|
|
<AtSign class="!size-5" />
|
|
|
|
|
</Button>
|
|
|
|
|
</TooltipTrigger>
|
|
|
|
|
<TooltipContent>
|
2024-12-07 22:17:22 +01:00
|
|
|
<p>{{ m.game_tough_seal_adore() }}</p>
|
2024-12-02 12:33:53 +01:00
|
|
|
</TooltipContent>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
<Tooltip>
|
|
|
|
|
<TooltipTrigger as="div">
|
2025-03-27 22:20:04 +01:00
|
|
|
<Toggle
|
|
|
|
|
variant="default"
|
|
|
|
|
size="sm"
|
2025-03-28 01:16:24 +01:00
|
|
|
:model-value="state.contentType === 'text/html'"
|
|
|
|
|
@update:model-value="
|
2025-03-27 22:20:04 +01:00
|
|
|
(i) =>
|
|
|
|
|
(state.contentType = i ? 'text/html' : 'text/plain')
|
|
|
|
|
"
|
|
|
|
|
>
|
2024-12-02 12:33:53 +01:00
|
|
|
<LetterText class="!size-5" />
|
|
|
|
|
</Toggle>
|
|
|
|
|
</TooltipTrigger>
|
|
|
|
|
<TooltipContent>
|
2024-12-07 22:17:22 +01:00
|
|
|
<p>{{ m.plane_born_koala_hope() }}</p>
|
2024-12-02 12:33:53 +01:00
|
|
|
</TooltipContent>
|
|
|
|
|
</Tooltip>
|
2024-12-01 15:30:42 +01:00
|
|
|
<Select v-model:model-value="state.visibility">
|
2025-03-27 22:20:04 +01:00
|
|
|
<SelectTrigger
|
|
|
|
|
:as-child="true"
|
|
|
|
|
:disabled="relation?.type === 'edit'"
|
2025-03-28 01:16:24 +01:00
|
|
|
:disable-default-classes="true"
|
|
|
|
|
:disable-select-icon="true"
|
2025-03-27 22:20:04 +01:00
|
|
|
>
|
2024-12-01 15:30:42 +01:00
|
|
|
<Button variant="ghost" size="icon">
|
2025-03-27 22:20:04 +01:00
|
|
|
<component
|
|
|
|
|
:is="visibilities[state.visibility].icon"
|
|
|
|
|
/>
|
2024-12-01 15:30:42 +01:00
|
|
|
</Button>
|
|
|
|
|
</SelectTrigger>
|
|
|
|
|
<SelectContent>
|
2025-03-27 22:20:04 +01:00
|
|
|
<SelectItem
|
|
|
|
|
v-for="(v, k) in visibilities"
|
|
|
|
|
:key="k"
|
|
|
|
|
@click="state.visibility = k"
|
|
|
|
|
:value="k"
|
|
|
|
|
>
|
|
|
|
|
<div
|
|
|
|
|
class="flex flex-row gap-4 items-center w-full justify-between"
|
|
|
|
|
>
|
2024-12-01 15:30:42 +01:00
|
|
|
<div class="flex flex-col gap-1">
|
|
|
|
|
<span class="font-semibold">{{ v.name }}</span>
|
|
|
|
|
<span>{{ v.text }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<component :is="v.icon" class="!size-5" />
|
|
|
|
|
</div>
|
|
|
|
|
</SelectItem>
|
|
|
|
|
</SelectContent>
|
|
|
|
|
</Select>
|
2024-12-02 12:33:53 +01:00
|
|
|
<Tooltip>
|
|
|
|
|
<TooltipTrigger as="div">
|
|
|
|
|
<Button variant="ghost" size="icon">
|
|
|
|
|
<Smile class="!size-5" />
|
|
|
|
|
</Button>
|
|
|
|
|
</TooltipTrigger>
|
|
|
|
|
<TooltipContent>
|
2024-12-07 22:17:22 +01:00
|
|
|
<p>{{ m.blue_ornate_coyote_tickle() }}</p>
|
2024-12-02 12:33:53 +01:00
|
|
|
</TooltipContent>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
<Tooltip>
|
|
|
|
|
<TooltipTrigger as="div">
|
|
|
|
|
<Button variant="ghost" size="icon" @click="fileInput?.click()">
|
|
|
|
|
<FilePlus2 class="!size-5" />
|
|
|
|
|
</Button>
|
|
|
|
|
</TooltipTrigger>
|
|
|
|
|
<TooltipContent>
|
2024-12-07 22:17:22 +01:00
|
|
|
<p>{{ m.top_patchy_earthworm_vent() }}</p>
|
2024-12-02 12:33:53 +01:00
|
|
|
</TooltipContent>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
<Tooltip>
|
|
|
|
|
<TooltipTrigger as="div">
|
2025-03-28 01:16:24 +01:00
|
|
|
<Toggle variant="default" size="sm" v-model="state.sensitive">
|
2024-12-02 12:33:53 +01:00
|
|
|
<TriangleAlert class="!size-5" />
|
|
|
|
|
</Toggle>
|
|
|
|
|
</TooltipTrigger>
|
|
|
|
|
<TooltipContent>
|
2024-12-07 22:17:22 +01:00
|
|
|
<p>{{ m.frail_broad_mallard_dart() }}</p>
|
2024-12-02 12:33:53 +01:00
|
|
|
</TooltipContent>
|
|
|
|
|
</Tooltip>
|
2025-03-27 22:20:04 +01:00
|
|
|
<Button
|
|
|
|
|
type="submit"
|
|
|
|
|
size="lg"
|
|
|
|
|
class="ml-auto"
|
|
|
|
|
:disabled="sending"
|
|
|
|
|
@click="submit"
|
|
|
|
|
>
|
2024-12-01 15:30:42 +01:00
|
|
|
<Loader v-if="sending" class="!size-5 animate-spin" />
|
2024-12-25 20:46:14 +01:00
|
|
|
{{
|
|
|
|
|
relation?.type === "edit"
|
|
|
|
|
? m.gaudy_strong_puma_slide()
|
|
|
|
|
: m.free_teal_bulldog_learn()
|
|
|
|
|
}}
|
2024-12-01 15:30:42 +01:00
|
|
|
</Button>
|
|
|
|
|
</DialogFooter>
|
2024-04-27 09:04:02 +02:00
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
2024-12-01 15:30:42 +01:00
|
|
|
import type { ResponseError } from "@versia/client";
|
2024-12-01 18:29:54 +01:00
|
|
|
import type { Status, StatusSource } from "@versia/client/types";
|
2024-11-30 19:15:23 +01:00
|
|
|
import {
|
|
|
|
|
AtSign,
|
|
|
|
|
FilePlus2,
|
2024-12-01 15:30:42 +01:00
|
|
|
Globe,
|
2024-11-30 19:15:23 +01:00
|
|
|
LetterText,
|
2024-12-01 15:30:42 +01:00
|
|
|
Loader,
|
|
|
|
|
Lock,
|
|
|
|
|
LockOpen,
|
2024-11-30 19:15:23 +01:00
|
|
|
Smile,
|
|
|
|
|
TriangleAlert,
|
|
|
|
|
} from "lucide-vue-next";
|
2024-12-01 15:30:42 +01:00
|
|
|
import { toast } from "vue-sonner";
|
2024-12-01 18:29:54 +01:00
|
|
|
import Note from "~/components/notes/note.vue";
|
2025-03-28 01:16:24 +01:00
|
|
|
import {
|
|
|
|
|
Select,
|
|
|
|
|
SelectContent,
|
|
|
|
|
SelectItem,
|
|
|
|
|
SelectTrigger,
|
|
|
|
|
} from "~/components/ui/select";
|
2024-12-07 22:17:22 +01:00
|
|
|
import * as m from "~/paraglide/messages.js";
|
2024-12-25 20:46:14 +01:00
|
|
|
import EditorContent from "../editor/content.vue";
|
2024-11-30 19:15:23 +01:00
|
|
|
import { Button } from "../ui/button";
|
2025-03-28 01:16:24 +01:00
|
|
|
import { DialogFooter } from "../ui/dialog";
|
2024-12-01 15:30:42 +01:00
|
|
|
import { Input } from "../ui/input";
|
|
|
|
|
import { Toggle } from "../ui/toggle";
|
2025-03-27 22:20:04 +01:00
|
|
|
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
|
2025-03-28 01:16:24 +01:00
|
|
|
import Files from "./files.vue";
|
2024-12-01 15:30:42 +01:00
|
|
|
|
|
|
|
|
const { Control_Enter, Command_Enter } = useMagicKeys();
|
2024-12-25 18:15:09 +01:00
|
|
|
const { play } = useAudio();
|
2024-12-01 17:20:21 +01:00
|
|
|
const fileInput = ref<HTMLInputElement | null>(null);
|
2024-11-30 19:15:23 +01:00
|
|
|
|
2024-12-01 15:30:42 +01:00
|
|
|
watch([Control_Enter, Command_Enter], () => {
|
2025-04-30 18:03:14 +02:00
|
|
|
if (sending.value || !preferences.ctrl_enter_send.value) {
|
2024-12-01 15:30:42 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
submit();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const { relation } = defineProps<{
|
2024-11-30 19:15:23 +01:00
|
|
|
relation?: {
|
2024-12-01 15:30:42 +01:00
|
|
|
type: "reply" | "quote" | "edit";
|
2024-11-30 19:15:23 +01:00
|
|
|
note: Status;
|
2024-12-01 18:29:54 +01:00
|
|
|
source?: StatusSource;
|
2024-11-30 19:15:23 +01:00
|
|
|
};
|
2024-04-27 09:04:02 +02:00
|
|
|
}>();
|
|
|
|
|
|
2024-12-02 21:48:02 +01:00
|
|
|
const getMentions = () => {
|
|
|
|
|
if (!relation || relation.type !== "reply") {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-25 17:25:16 +01:00
|
|
|
const note = relation.note.reblog || relation.note;
|
|
|
|
|
|
|
|
|
|
const peopleToMention = note.mentions
|
|
|
|
|
.concat(note.account)
|
2024-12-02 21:48:02 +01:00
|
|
|
// Deduplicate mentions
|
2024-12-07 22:17:22 +01:00
|
|
|
.filter((men, i, a) => a.indexOf(men) === i)
|
2024-12-02 21:48:02 +01:00
|
|
|
// Remove self
|
2024-12-07 22:17:22 +01:00
|
|
|
.filter((men) => men.id !== identity.value?.account.id);
|
2024-12-02 21:48:02 +01:00
|
|
|
|
2024-12-25 17:25:16 +01:00
|
|
|
if (peopleToMention.length === 0) {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-07 22:17:22 +01:00
|
|
|
const mentions = peopleToMention.map((me) => `@${me.acct}`).join(" ");
|
2024-12-02 21:48:02 +01:00
|
|
|
|
|
|
|
|
return `${mentions} `;
|
|
|
|
|
};
|
|
|
|
|
|
2024-12-01 15:30:42 +01:00
|
|
|
const state = reactive({
|
2024-12-02 21:48:02 +01:00
|
|
|
// If editing, use the original content
|
|
|
|
|
// If sending a reply, prefill with mentions
|
|
|
|
|
content: relation?.source?.text || getMentions(),
|
2024-12-01 18:29:54 +01:00
|
|
|
sensitive: relation?.type === "edit" ? relation.note.sensitive : false,
|
|
|
|
|
contentWarning: relation?.type === "edit" ? relation.note.spoiler_text : "",
|
2024-12-25 20:46:14 +01:00
|
|
|
contentType: "text/html" as "text/html" | "text/plain",
|
2025-04-30 18:03:14 +02:00
|
|
|
visibility:
|
|
|
|
|
relation?.type === "edit"
|
|
|
|
|
? relation.note.visibility
|
|
|
|
|
: preferences.default_visibility.value,
|
2024-12-01 18:29:54 +01:00
|
|
|
files: (relation?.type === "edit"
|
2024-12-07 22:17:22 +01:00
|
|
|
? relation.note.media_attachments.map((a) => ({
|
|
|
|
|
apiId: a.id,
|
|
|
|
|
file: new File([], a.url),
|
|
|
|
|
alt: a.description,
|
2024-12-01 18:29:54 +01:00
|
|
|
uploading: false,
|
|
|
|
|
updating: false,
|
|
|
|
|
}))
|
|
|
|
|
: []) as {
|
2024-12-01 15:30:42 +01:00
|
|
|
apiId?: string;
|
|
|
|
|
file: File;
|
2024-12-01 17:20:21 +01:00
|
|
|
alt?: string;
|
2024-12-01 15:30:42 +01:00
|
|
|
uploading: boolean;
|
|
|
|
|
updating: boolean;
|
|
|
|
|
}[],
|
|
|
|
|
});
|
|
|
|
|
const sending = ref(false);
|
|
|
|
|
|
2024-11-30 19:15:23 +01:00
|
|
|
const splashes = useConfig().COMPOSER_SPLASHES;
|
|
|
|
|
const chosenSplash = splashes[Math.floor(Math.random() * splashes.length)];
|
2024-12-01 15:30:42 +01:00
|
|
|
|
|
|
|
|
const submit = async () => {
|
|
|
|
|
sending.value = true;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
if (relation?.type === "edit") {
|
2024-12-02 10:29:03 +01:00
|
|
|
const { data } = await client.value.editStatus(relation.note.id, {
|
2024-12-01 15:30:42 +01:00
|
|
|
status: state.content,
|
|
|
|
|
content_type: state.contentType,
|
|
|
|
|
sensitive: state.sensitive,
|
|
|
|
|
spoiler_text: state.sensitive
|
|
|
|
|
? state.contentWarning
|
|
|
|
|
: undefined,
|
|
|
|
|
media_ids: state.files
|
|
|
|
|
.map((f) => f.apiId)
|
|
|
|
|
.filter((f) => f !== undefined),
|
|
|
|
|
});
|
|
|
|
|
|
2024-12-02 10:29:03 +01:00
|
|
|
useEvent("composer:send-edit", data);
|
2024-12-25 18:15:09 +01:00
|
|
|
play("publish");
|
2024-12-07 15:16:45 +01:00
|
|
|
useEvent("composer:close");
|
2024-12-02 10:29:03 +01:00
|
|
|
} else {
|
|
|
|
|
const { data } = await client.value.postStatus(state.content, {
|
|
|
|
|
content_type: state.contentType,
|
|
|
|
|
sensitive: state.sensitive,
|
|
|
|
|
spoiler_text: state.sensitive
|
|
|
|
|
? state.contentWarning
|
|
|
|
|
: undefined,
|
|
|
|
|
media_ids: state.files
|
|
|
|
|
.map((f) => f.apiId)
|
|
|
|
|
.filter((f) => f !== undefined),
|
|
|
|
|
quote_id:
|
|
|
|
|
relation?.type === "quote" ? relation.note.id : undefined,
|
|
|
|
|
in_reply_to_id:
|
|
|
|
|
relation?.type === "reply" ? relation.note.id : undefined,
|
|
|
|
|
visibility: state.visibility,
|
|
|
|
|
});
|
2024-12-01 15:30:42 +01:00
|
|
|
|
2024-12-02 10:29:03 +01:00
|
|
|
useEvent("composer:send", data as Status);
|
2024-12-25 18:15:09 +01:00
|
|
|
play("publish");
|
2024-12-02 10:29:03 +01:00
|
|
|
useEvent("composer:close");
|
|
|
|
|
}
|
2024-12-01 15:30:42 +01:00
|
|
|
} catch (_e) {
|
|
|
|
|
const e = _e as ResponseError;
|
|
|
|
|
toast.error(e.message);
|
|
|
|
|
} finally {
|
|
|
|
|
sending.value = false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2024-12-01 17:20:21 +01:00
|
|
|
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);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2024-12-01 15:30:42 +01:00
|
|
|
const visibilities = {
|
|
|
|
|
public: {
|
|
|
|
|
icon: Globe,
|
2024-12-07 22:17:22 +01:00
|
|
|
name: m.lost_trick_dog_grace(),
|
|
|
|
|
text: m.last_mean_peacock_zip(),
|
2024-12-01 15:30:42 +01:00
|
|
|
},
|
|
|
|
|
unlisted: {
|
|
|
|
|
icon: LockOpen,
|
2024-12-07 22:17:22 +01:00
|
|
|
name: m.funny_slow_jannes_walk(),
|
|
|
|
|
text: m.grand_strong_gibbon_race(),
|
2024-12-01 15:30:42 +01:00
|
|
|
},
|
|
|
|
|
private: {
|
|
|
|
|
icon: Lock,
|
2024-12-07 22:17:22 +01:00
|
|
|
name: m.grassy_empty_raven_startle(),
|
|
|
|
|
text: m.white_teal_ostrich_yell(),
|
2024-12-01 15:30:42 +01:00
|
|
|
},
|
|
|
|
|
direct: {
|
|
|
|
|
icon: AtSign,
|
2024-12-07 22:17:22 +01:00
|
|
|
name: m.pretty_bold_baboon_wave(),
|
|
|
|
|
text: m.lucky_mean_robin_link(),
|
2024-12-01 15:30:42 +01:00
|
|
|
},
|
|
|
|
|
};
|
2024-12-17 12:30:01 +01:00
|
|
|
</script>
|