|
1 | 1 | <template>
|
2 |
| - <div v-if="respondingTo" class="mb-4"> |
| 2 | + <div v-if="respondingTo" class="mb-4" role="region" aria-label="Responding to"> |
3 | 3 | <OverlayScrollbarsComponent :defer="true" class="max-h-72 overflow-y-auto">
|
4 | 4 | <LazySocialElementsNotesNote :note="respondingTo" :small="true" :disabled="true"
|
5 | 5 | class="!rounded-none !bg-pink-500/10" />
|
6 | 6 | </OverlayScrollbarsComponent>
|
7 | 7 | </div>
|
8 | 8 | <div class="px-6 pb-4 pt-5">
|
9 | 9 | <div class="pb-2 relative">
|
10 |
| - <textarea :disabled="submitting" ref="textarea" v-model="content" :placeholder="chosenSplash" |
| 10 | + <textarea :disabled="loading" ref="textarea" v-model="content" :placeholder="chosenSplash" |
11 | 11 | @paste="handlePaste"
|
12 |
| - class="resize-none min-h-48 prose prose-invert max-h-[70dvh] w-full p-0 focus:!ring-0 !ring-none !border-none !outline-none placeholder:text-zinc-500 bg-transparent appearance-none focus:!border-none focus:!outline-none disabled:cursor-not-allowed"></textarea> |
13 |
| - <div |
14 |
| - :class="['absolute bottom-0 right-0 p-2 text-gray-400 font-semibold text-xs', remainingCharacters < 0 && 'text-red-500']"> |
| 12 | + class="resize-none min-h-48 prose prose-invert max-h-[70dvh] w-full p-0 focus:!ring-0 !ring-none !border-none !outline-none placeholder:text-zinc-500 bg-transparent appearance-none focus:!border-none focus:!outline-none disabled:cursor-not-allowed" |
| 13 | + aria-label="Compose your message"></textarea> |
| 14 | + <div :class="['absolute bottom-0 right-0 p-2 text-gray-400 font-semibold text-xs', remainingCharacters < 0 && 'text-red-500']" |
| 15 | + aria-live="polite"> |
15 | 16 | {{ remainingCharacters }}
|
16 | 17 | </div>
|
17 | 18 | <ComposerEmojiSuggestbox :currently-typing-emoji="currentlyBeingTypedEmoji"
|
|
20 | 21 | <!-- Content warning textbox -->
|
21 | 22 | <div v-if="cw" class="mb-4">
|
22 | 23 | <input type="text" v-model="cwContent" placeholder="Add a content warning"
|
23 |
| - class="w-full p-2 mt-1 text-sm prose prose-invert bg-dark-900 rounded focus:!ring-0 !ring-none !border-none !outline-none placeholder:text-zinc-500 appearance-none focus:!border-none focus:!outline-none" /> |
| 24 | + class="w-full p-2 mt-1 text-sm prose prose-invert bg-dark-900 rounded focus:!ring-0 !ring-none !border-none !outline-none placeholder:text-zinc-500 appearance-none focus:!border-none focus:!outline-none" |
| 25 | + aria-label="Content warning" /> |
24 | 26 | </div>
|
25 | 27 | <ComposerFileUploader v-model:files="files" ref="uploader" />
|
26 | 28 | <div class="flex flex-row gap-1 border-white/20">
|
|
43 | 45 | <ComposerButton title="Add content warning" @click="cw = !cw" :toggled="cw">
|
44 | 46 | <iconify-icon width="1.25rem" height="1.25rem" icon="tabler:rating-18-plus" aria-hidden="true" />
|
45 | 47 | </ComposerButton>
|
46 |
| - <ButtonsPrimary :loading="submitting" @click="send" class="ml-auto rounded-full"> |
| 48 | + <ButtonsPrimary :loading="loading" @click="send" class="ml-auto rounded-full"> |
47 | 49 | <span>Send!</span>
|
48 | 50 | </ButtonsPrimary>
|
49 | 51 | </div>
|
@@ -99,6 +101,7 @@ const files = ref<
|
99 | 101 | file: File;
|
100 | 102 | progress: number;
|
101 | 103 | api_id?: string;
|
| 104 | + alt_text?: string; |
102 | 105 | }[]
|
103 | 106 | >([]);
|
104 | 107 |
|
@@ -126,6 +129,21 @@ watch(Control_Alt, () => {
|
126 | 129 | chosenSplash.value = splashes[Math.floor(Math.random() * splashes.length)];
|
127 | 130 | });
|
128 | 131 |
|
| 132 | +watch( |
| 133 | + files, |
| 134 | + (newFiles) => { |
| 135 | + // If a file is uploading, set loading to true |
| 136 | + if (newFiles.some((file) => file.progress < 1)) { |
| 137 | + loading.value = true; |
| 138 | + } else { |
| 139 | + loading.value = false; |
| 140 | + } |
| 141 | + }, |
| 142 | + { |
| 143 | + deep: true, |
| 144 | + }, |
| 145 | +); |
| 146 | +
|
129 | 147 | onMounted(() => {
|
130 | 148 | useListen("composer:reply", (note: Status) => {
|
131 | 149 | respondingTo.value = note;
|
@@ -154,12 +172,12 @@ const props = defineProps<{
|
154 | 172 | instance: Instance;
|
155 | 173 | }>();
|
156 | 174 |
|
157 |
| -const submitting = ref(false); |
| 175 | +const loading = ref(false); |
158 | 176 | const tokenData = useTokenData();
|
159 | 177 | const client = useMegalodon(tokenData);
|
160 | 178 |
|
161 | 179 | const send = async () => {
|
162 |
| - submitting.value = true; |
| 180 | + loading.value = true; |
163 | 181 |
|
164 | 182 | fetch(new URL("/api/v1/statuses", client.value?.baseUrl ?? "").toString(), {
|
165 | 183 | method: "POST",
|
@@ -191,7 +209,7 @@ const send = async () => {
|
191 | 209 | }
|
192 | 210 |
|
193 | 211 | content.value = "";
|
194 |
| - submitting.value = false; |
| 212 | + loading.value = false; |
195 | 213 | useEvent("composer:send", await res.json());
|
196 | 214 | })
|
197 | 215 | .finally(() => {
|
|
0 commit comments