fix types
This commit is contained in:
parent
3e43819ba1
commit
16880b1231
16 changed files with 135 additions and 102 deletions
1
packages/client/@types/global.d.ts
vendored
1
packages/client/@types/global.d.ts
vendored
|
@ -1,3 +1,4 @@
|
|||
// biome-ignore lint/suspicious/noExplicitAny:
|
||||
type FIXME = any;
|
||||
|
||||
declare const _LANGS_: string[][];
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<article
|
||||
v-if="!muted.muted || muted.what === 'reply'"
|
||||
:id="detailedView ? appearNote.id : null"
|
||||
:id="detailedView ? appearNote.id : undefined"
|
||||
ref="el"
|
||||
v-size="{ max: [450, 500] }"
|
||||
class="wrpstxzv"
|
||||
|
@ -35,10 +35,10 @@
|
|||
:parent-id="parentId"
|
||||
:conversation="conversation"
|
||||
:detailed-view="detailedView"
|
||||
@focusfooter="footerEl.focus()"
|
||||
@focusfooter="footerEl!.focus()"
|
||||
/>
|
||||
<div v-if="translating || translation" class="translation">
|
||||
<MkLoading v-if="translating" mini />
|
||||
<MkLoading v-if="translating || translation == null" mini />
|
||||
<div v-else class="translated">
|
||||
<b
|
||||
>{{
|
||||
|
@ -217,6 +217,7 @@ import { useNoteCapture } from "@/scripts/use-note-capture";
|
|||
import { defaultStore } from "@/store";
|
||||
import { deepClone } from "@/scripts/clone";
|
||||
import icon from "@/scripts/icon";
|
||||
import type { NoteTranslation } from "@/types/note";
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
|
@ -256,12 +257,12 @@ const isRenote =
|
|||
note.value.fileIds.length === 0 &&
|
||||
note.value.poll == null;
|
||||
|
||||
const el = ref<HTMLElement>();
|
||||
const footerEl = ref<HTMLElement>();
|
||||
const el = ref<HTMLElement | null>(null);
|
||||
const footerEl = ref<HTMLElement | null>(null);
|
||||
const menuButton = ref<HTMLElement>();
|
||||
const starButton = ref<InstanceType<typeof XStarButton>>();
|
||||
const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
|
||||
const reactButton = ref<HTMLElement>();
|
||||
const starButton = ref<InstanceType<typeof XStarButton> | null>(null);
|
||||
const renoteButton = ref<InstanceType<typeof XRenoteButton> | null>(null);
|
||||
const reactButton = ref<HTMLElement | null>(null);
|
||||
const appearNote = computed(() =>
|
||||
isRenote ? (note.value.renote as entities.Note) : note.value,
|
||||
);
|
||||
|
@ -274,7 +275,7 @@ const muted = ref(
|
|||
defaultStore.state.mutedLangs,
|
||||
),
|
||||
);
|
||||
const translation = ref(null);
|
||||
const translation = ref<NoteTranslation | null>(null);
|
||||
const translating = ref(false);
|
||||
const replies: entities.Note[] =
|
||||
props.conversation
|
||||
|
@ -330,21 +331,21 @@ useNoteCapture({
|
|||
isDeletedRef: isDeleted,
|
||||
});
|
||||
|
||||
function reply(viaKeyboard = false): void {
|
||||
function reply(_viaKeyboard = false): void {
|
||||
pleaseLogin();
|
||||
os.post({
|
||||
reply: appearNote.value,
|
||||
animation: !viaKeyboard,
|
||||
// animation: !viaKeyboard,
|
||||
}).then(() => {
|
||||
focus();
|
||||
});
|
||||
}
|
||||
|
||||
function react(viaKeyboard = false): void {
|
||||
function react(_viaKeyboard = false): void {
|
||||
pleaseLogin();
|
||||
blur();
|
||||
reactionPicker.show(
|
||||
reactButton.value,
|
||||
reactButton.value!,
|
||||
(reaction) => {
|
||||
os.api("notes/reactions/create", {
|
||||
noteId: appearNote.value.id,
|
||||
|
@ -388,14 +389,15 @@ function menu(viaKeyboard = false): void {
|
|||
}
|
||||
|
||||
function onContextmenu(ev: MouseEvent): void {
|
||||
const isLink = (el: HTMLElement) => {
|
||||
const isLink = (el: HTMLElement | null) => {
|
||||
if (el == null) return;
|
||||
if (el.tagName === "A") return true;
|
||||
if (el.parentElement) {
|
||||
return isLink(el.parentElement);
|
||||
}
|
||||
};
|
||||
if (isLink(ev.target)) return;
|
||||
if (window.getSelection().toString() !== "") return;
|
||||
if (isLink(ev.target as HTMLElement | null)) return;
|
||||
if (window.getSelection()?.toString() !== "") return;
|
||||
|
||||
if (defaultStore.state.useReactionPickerForContextMenu) {
|
||||
ev.preventDefault();
|
||||
|
@ -454,15 +456,15 @@ function onContextmenu(ev: MouseEvent): void {
|
|||
}
|
||||
|
||||
function focus() {
|
||||
el.value.focus();
|
||||
el.value!.focus();
|
||||
}
|
||||
|
||||
function blur() {
|
||||
el.value.blur();
|
||||
el.value!.blur();
|
||||
}
|
||||
|
||||
function noteClick(e) {
|
||||
if (document.getSelection().type === "Range" || !expandOnNoteClick) {
|
||||
function noteClick(e: MouseEvent) {
|
||||
if (document.getSelection()?.type === "Range" || !expandOnNoteClick) {
|
||||
e.stopPropagation();
|
||||
} else {
|
||||
router.push(notePage(props.note));
|
||||
|
|
|
@ -84,14 +84,10 @@ import { formatDateTimeString } from "@/scripts/format-time-string";
|
|||
import { addTime } from "@/scripts/time";
|
||||
import { i18n } from "@/i18n";
|
||||
import icon from "@/scripts/icon";
|
||||
import type { PollType } from "@/types/post-form";
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: {
|
||||
expiresAt: string;
|
||||
expiredAfter: number;
|
||||
choices: string[];
|
||||
multiple: boolean;
|
||||
};
|
||||
modelValue: PollType;
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
"update:modelValue": [
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
class="account _button"
|
||||
@click="openAccountMenu"
|
||||
>
|
||||
<MkAvatar :user="postAccount ?? me" class="avatar" />
|
||||
<MkAvatar :user="postAccount ?? me!" class="avatar" />
|
||||
</button>
|
||||
<div class="right">
|
||||
<span
|
||||
|
@ -297,14 +297,22 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, inject, nextTick, onMounted, ref, watch } from "vue";
|
||||
import {
|
||||
type Ref,
|
||||
computed,
|
||||
inject,
|
||||
nextTick,
|
||||
onMounted,
|
||||
ref,
|
||||
watch,
|
||||
} from "vue";
|
||||
import * as mfm from "mfm-js";
|
||||
import autosize from "autosize";
|
||||
import insertTextAtCursor from "insert-text-at-cursor";
|
||||
import { length } from "stringz";
|
||||
import { toASCII } from "punycode/";
|
||||
import { acct } from "firefish-js";
|
||||
import type { entities, languages } from "firefish-js";
|
||||
import type { ApiTypes, entities, languages } from "firefish-js";
|
||||
import { throttle } from "throttle-debounce";
|
||||
import XNoteSimple from "@/components/MkNoteSimple.vue";
|
||||
import XNotePreview from "@/components/MkNotePreview.vue";
|
||||
|
@ -341,6 +349,7 @@ import type { MenuItem } from "@/types/menu";
|
|||
import icon from "@/scripts/icon";
|
||||
import MkVisibilityPicker from "@/components/MkVisibilityPicker.vue";
|
||||
import type { NoteVisibility } from "@/types/note";
|
||||
import type { NoteDraft, PollType } from "@/types/post-form";
|
||||
|
||||
const modal = inject("modal");
|
||||
|
||||
|
@ -353,11 +362,11 @@ const props = withDefaults(
|
|||
specified?: entities.User;
|
||||
initialText?: string;
|
||||
initialVisibility?: NoteVisibility;
|
||||
initialLanguage?: typeof languages;
|
||||
initialLanguage?: (typeof languages)[number];
|
||||
initialFiles?: entities.DriveFile[];
|
||||
initialLocalOnly?: boolean;
|
||||
initialVisibleUsers?: entities.User[];
|
||||
initialNote?: entities.Note;
|
||||
initialNote?: NoteDraft;
|
||||
instant?: boolean;
|
||||
fixed?: boolean;
|
||||
autofocus?: boolean;
|
||||
|
@ -390,12 +399,7 @@ const showBigPostButton = defaultStore.state.showBigPostButton;
|
|||
const posting = ref(false);
|
||||
const text = ref(props.initialText ?? "");
|
||||
const files = ref(props.initialFiles ?? ([] as entities.DriveFile[]));
|
||||
const poll = ref<{
|
||||
choices: string[];
|
||||
multiple: boolean;
|
||||
expiresAt: string | null;
|
||||
expiredAfter: string | null;
|
||||
} | null>(null);
|
||||
const poll = ref<PollType | null>(null);
|
||||
const useCw = ref(false);
|
||||
const showPreview = ref(defaultStore.state.showPreviewByDefault);
|
||||
const cw = ref<string | null>(null);
|
||||
|
@ -411,12 +415,12 @@ const visibility = ref(
|
|||
: defaultStore.state.defaultNoteVisibility),
|
||||
);
|
||||
|
||||
const visibleUsers = ref([]);
|
||||
const visibleUsers = ref<entities.User[]>([]);
|
||||
if (props.initialVisibleUsers) {
|
||||
props.initialVisibleUsers.forEach(pushVisibleUser);
|
||||
}
|
||||
const draghover = ref(false);
|
||||
const quoteId = ref(null);
|
||||
const quoteId = ref<string | null>(null);
|
||||
const hasNotSpecifiedMentions = ref(false);
|
||||
const recentHashtags = ref(
|
||||
JSON.parse(localStorage.getItem("hashtags") || "[]"),
|
||||
|
@ -500,7 +504,9 @@ const canPost = computed((): boolean => {
|
|||
const withHashtags = computed(
|
||||
defaultStore.makeGetterSetter("postFormWithHashtags"),
|
||||
);
|
||||
const hashtags = computed(defaultStore.makeGetterSetter("postFormHashtags"));
|
||||
const hashtags = computed(
|
||||
defaultStore.makeGetterSetter("postFormHashtags"),
|
||||
) as Ref<string | null>;
|
||||
|
||||
watch(text, () => {
|
||||
checkMissingMention();
|
||||
|
@ -525,7 +531,7 @@ if (props.mention) {
|
|||
|
||||
if (
|
||||
props.reply &&
|
||||
(props.reply.user.username !== me.username ||
|
||||
(props.reply.user.username !== me!.username ||
|
||||
(props.reply.user.host != null && props.reply.user.host !== host))
|
||||
) {
|
||||
text.value = `@${props.reply.user.username}${
|
||||
|
@ -545,7 +551,7 @@ if (props.reply && props.reply.text != null) {
|
|||
: `@${x.username}@${toASCII(otherHost)}`;
|
||||
|
||||
// exclude me
|
||||
if (me.username === x.username && (x.host == null || x.host === host))
|
||||
if (me!.username === x.username && (x.host == null || x.host === host))
|
||||
continue;
|
||||
|
||||
// remove duplicates
|
||||
|
@ -579,7 +585,7 @@ if (
|
|||
if (props.reply.visibleUserIds) {
|
||||
os.api("users/show", {
|
||||
userIds: props.reply.visibleUserIds.filter(
|
||||
(uid) => uid !== me.id && uid !== props.reply.userId,
|
||||
(uid) => uid !== me!.id && uid !== props.reply!.userId,
|
||||
),
|
||||
}).then((users) => {
|
||||
users.forEach(pushVisibleUser);
|
||||
|
@ -588,7 +594,7 @@ if (
|
|||
visibility.value = "private";
|
||||
}
|
||||
|
||||
if (props.reply.userId !== me.id) {
|
||||
if (props.reply.userId !== me!.id) {
|
||||
os.api("users/show", { userId: props.reply.userId }).then((user) => {
|
||||
pushVisibleUser(user);
|
||||
});
|
||||
|
@ -615,7 +621,7 @@ const addRe = (s: string) => {
|
|||
if (defaultStore.state.keepCw && props.reply && props.reply.cw) {
|
||||
useCw.value = true;
|
||||
cw.value =
|
||||
props.reply.user.username === me.username
|
||||
props.reply.user.username === me!.username
|
||||
? props.reply.cw
|
||||
: addRe(props.reply.cw);
|
||||
}
|
||||
|
@ -894,11 +900,14 @@ function onCompositionEnd(ev: CompositionEvent) {
|
|||
}
|
||||
|
||||
async function onPaste(ev: ClipboardEvent) {
|
||||
if (ev.clipboardData == null) return;
|
||||
|
||||
for (const { item, i } of Array.from(ev.clipboardData.items).map(
|
||||
(item, i) => ({ item, i }),
|
||||
)) {
|
||||
if (item.kind === "file") {
|
||||
const file = item.getAsFile();
|
||||
if (file == null) continue;
|
||||
const lio = file.name.lastIndexOf(".");
|
||||
const ext = lio >= 0 ? file.name.slice(lio) : "";
|
||||
const formatted = `${formatTimeString(
|
||||
|
@ -911,7 +920,7 @@ async function onPaste(ev: ClipboardEvent) {
|
|||
|
||||
const paste = ev.clipboardData?.getData("text") ?? "";
|
||||
|
||||
if (!props.renote && !quoteId.value && paste.startsWith(url + "/notes/")) {
|
||||
if (!props.renote && !quoteId.value && paste.startsWith(`${url}/notes/`)) {
|
||||
ev.preventDefault();
|
||||
|
||||
os.yesno({
|
||||
|
@ -919,13 +928,13 @@ async function onPaste(ev: ClipboardEvent) {
|
|||
text: i18n.ts.quoteQuestion,
|
||||
}).then(({ canceled }) => {
|
||||
if (canceled) {
|
||||
insertTextAtCursor(textareaEl.value, paste);
|
||||
insertTextAtCursor(textareaEl.value!, paste);
|
||||
return;
|
||||
}
|
||||
|
||||
quoteId.value = paste
|
||||
.substring(url.length)
|
||||
.match(/^\/notes\/(.+?)\/?$/)[1];
|
||||
.match(/^\/notes\/(.+?)\/?$/)![1];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -956,16 +965,17 @@ function onDragover(ev) {
|
|||
}
|
||||
}
|
||||
|
||||
function onDragenter(ev) {
|
||||
function onDragenter(_ev) {
|
||||
draghover.value = true;
|
||||
}
|
||||
|
||||
function onDragleave(ev) {
|
||||
function onDragleave(_ev) {
|
||||
draghover.value = false;
|
||||
}
|
||||
|
||||
function onDrop(ev): void {
|
||||
function onDrop(ev: DragEvent): void {
|
||||
draghover.value = false;
|
||||
if (ev.dataTransfer == null) return;
|
||||
|
||||
// ファイルだったら
|
||||
if (ev.dataTransfer.files.length > 0) {
|
||||
|
@ -1064,7 +1074,7 @@ async function post() {
|
|||
|
||||
const processedText = preprocess(text.value);
|
||||
|
||||
let postData = {
|
||||
let postData: ApiTypes.NoteSubmitReq = {
|
||||
editId: props.editId ? props.editId : undefined,
|
||||
text: processedText === "" ? undefined : processedText,
|
||||
fileIds: files.value.length > 0 ? files.value.map((f) => f.id) : undefined,
|
||||
|
@ -1092,7 +1102,7 @@ async function post() {
|
|||
const hashtags_ = hashtags.value
|
||||
.trim()
|
||||
.split(" ")
|
||||
.map((x) => (x.startsWith("#") ? x : "#" + x))
|
||||
.map((x) => (x.startsWith("#") ? x : `#${x}`))
|
||||
.join(" ");
|
||||
postData.text = postData.text ? `${postData.text} ${hashtags_}` : hashtags_;
|
||||
}
|
||||
|
@ -1104,11 +1114,11 @@ async function post() {
|
|||
}
|
||||
}
|
||||
|
||||
let token;
|
||||
let token: string | undefined;
|
||||
|
||||
if (postAccount.value) {
|
||||
const storedAccounts = await getAccounts();
|
||||
token = storedAccounts.find((x) => x.id === postAccount.value.id)?.token;
|
||||
token = storedAccounts.find((x) => x.id === postAccount.value!.id)?.token;
|
||||
}
|
||||
|
||||
posting.value = true;
|
||||
|
@ -1119,10 +1129,11 @@ async function post() {
|
|||
deleteDraft();
|
||||
emit("posted");
|
||||
if (postData.text && postData.text !== "") {
|
||||
const hashtags_ = mfm
|
||||
const hashtags_ = (
|
||||
mfm
|
||||
.parse(postData.text)
|
||||
.filter((x) => x.type === "hashtag")
|
||||
.map((x) => x.props.hashtag);
|
||||
.filter((x) => x.type === "hashtag") as mfm.MfmHashtag[]
|
||||
).map((x) => x.props.hashtag);
|
||||
const history = JSON.parse(
|
||||
localStorage.getItem("hashtags") || "[]",
|
||||
) as string[];
|
||||
|
@ -1133,7 +1144,7 @@ async function post() {
|
|||
}
|
||||
posting.value = false;
|
||||
postAccount.value = null;
|
||||
nextTick(() => autosize.update(textareaEl.value));
|
||||
nextTick(() => autosize.update(textareaEl.value!));
|
||||
});
|
||||
})
|
||||
.catch((err: { message: string; id: string }) => {
|
||||
|
@ -1169,19 +1180,23 @@ function cancel() {
|
|||
|
||||
function insertMention() {
|
||||
os.selectUser().then((user) => {
|
||||
insertTextAtCursor(textareaEl.value, "@" + acct.toString(user) + " ");
|
||||
insertTextAtCursor(textareaEl.value!, `@${acct.toString(user)} `);
|
||||
});
|
||||
}
|
||||
|
||||
async function insertEmoji(ev: MouseEvent) {
|
||||
os.openEmojiPicker(ev.currentTarget ?? ev.target, {}, textareaEl.value);
|
||||
os.openEmojiPicker(
|
||||
(ev.currentTarget ?? ev.target) as HTMLElement,
|
||||
{},
|
||||
textareaEl.value,
|
||||
);
|
||||
}
|
||||
|
||||
async function openCheatSheet(ev: MouseEvent) {
|
||||
os.popup(XCheatSheet, {}, {}, "closed");
|
||||
}
|
||||
|
||||
function showActions(ev) {
|
||||
function showActions(ev: MouseEvent) {
|
||||
os.popupMenu(
|
||||
postFormActions.map((action) => ({
|
||||
text: action.title,
|
||||
|
@ -1198,7 +1213,7 @@ function showActions(ev) {
|
|||
);
|
||||
},
|
||||
})),
|
||||
ev.currentTarget ?? ev.target,
|
||||
(ev.currentTarget ?? ev.target) as HTMLElement,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1209,9 +1224,9 @@ function openAccountMenu(ev: MouseEvent) {
|
|||
{
|
||||
withExtraOperation: false,
|
||||
includeCurrentAccount: true,
|
||||
active: postAccount.value != null ? postAccount.value.id : me.id,
|
||||
active: postAccount.value != null ? postAccount.value.id : me!.id,
|
||||
onChoose: (account) => {
|
||||
if (account.id === me.id) {
|
||||
if (account.id === me!.id) {
|
||||
postAccount.value = null;
|
||||
} else {
|
||||
postAccount.value = account;
|
||||
|
@ -1232,14 +1247,14 @@ onMounted(() => {
|
|||
}
|
||||
|
||||
// TODO: detach when unmount
|
||||
new Autocomplete(textareaEl.value, text);
|
||||
new Autocomplete(cwInputEl.value, cw);
|
||||
new Autocomplete(hashtagsInputEl.value, hashtags);
|
||||
new Autocomplete(textareaEl.value!, text);
|
||||
new Autocomplete(cwInputEl.value!, cw as Ref<string>);
|
||||
new Autocomplete(hashtagsInputEl.value!, hashtags as Ref<string>);
|
||||
|
||||
autosize(textareaEl.value);
|
||||
autosize(textareaEl.value!);
|
||||
|
||||
nextTick(() => {
|
||||
autosize(textareaEl.value);
|
||||
autosize(textareaEl.value!);
|
||||
// 書きかけの投稿を復元
|
||||
if (!props.instant && !props.mention && !props.specified) {
|
||||
const draft = JSON.parse(localStorage.getItem("drafts") || "{}")[
|
||||
|
@ -1275,8 +1290,8 @@ onMounted(() => {
|
|||
};
|
||||
}
|
||||
visibility.value = init.visibility;
|
||||
localOnly.value = init.localOnly;
|
||||
language.value = init.lang;
|
||||
localOnly.value = init.localOnly ?? false;
|
||||
language.value = init.lang ?? null;
|
||||
quoteId.value = init.renote ? init.renote.id : null;
|
||||
}
|
||||
|
||||
|
@ -1289,7 +1304,7 @@ onMounted(() => {
|
|||
}
|
||||
|
||||
nextTick(() => watchForDraft());
|
||||
nextTick(() => autosize.update(textareaEl.value));
|
||||
nextTick(() => autosize.update(textareaEl.value!));
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -25,6 +25,7 @@ import type { entities, languages } from "firefish-js";
|
|||
import MkModal from "@/components/MkModal.vue";
|
||||
import MkPostForm from "@/components/MkPostForm.vue";
|
||||
import type { NoteVisibility } from "@/types/note";
|
||||
import type { NoteDraft } from "@/types/post-form";
|
||||
|
||||
const props = defineProps<{
|
||||
reply?: entities.Note;
|
||||
|
@ -34,11 +35,11 @@ const props = defineProps<{
|
|||
specified?: entities.User;
|
||||
initialText?: string;
|
||||
initialVisibility?: NoteVisibility;
|
||||
initialLanguage?: typeof languages;
|
||||
initialLanguage?: (typeof languages)[number];
|
||||
initialFiles?: entities.DriveFile[];
|
||||
initialLocalOnly?: boolean;
|
||||
initialVisibleUsers?: entities.User[];
|
||||
initialNote?: entities.Note;
|
||||
initialNote?: NoteDraft;
|
||||
instant?: boolean;
|
||||
fixed?: boolean;
|
||||
autofocus?: boolean;
|
||||
|
@ -53,7 +54,7 @@ const modal = shallowRef<InstanceType<typeof MkModal>>();
|
|||
const form = shallowRef<InstanceType<typeof MkPostForm>>();
|
||||
|
||||
function onPosted() {
|
||||
modal.value.close({
|
||||
modal.value!.close({
|
||||
useSendAnimation: true,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -319,7 +319,7 @@ const usernameState = ref<
|
|||
| "invalid-format"
|
||||
| "min-range"
|
||||
| "max-range"
|
||||
>(null);
|
||||
>(null);
|
||||
const invitationState = ref<null | "entered">(null);
|
||||
const emailState = ref<
|
||||
| null
|
||||
|
@ -331,9 +331,10 @@ const emailState = ref<
|
|||
| "unavailable:mx"
|
||||
| "unavailable:smtp"
|
||||
| "unavailable"
|
||||
| "error">(null);
|
||||
| "error"
|
||||
>(null);
|
||||
const passwordStrength = ref<"" | "low" | "medium" | "high">("");
|
||||
const passwordRetypeState = ref<null | "match" | "not-match" >(null);
|
||||
const passwordRetypeState = ref<null | "match" | "not-match">(null);
|
||||
const submitting = ref(false);
|
||||
const ToSAgreement = ref(false);
|
||||
const hCaptchaResponse = ref(null);
|
||||
|
|
|
@ -76,6 +76,7 @@ onMounted(() => {
|
|||
src: "/client-assets/tagcanvas.min.js",
|
||||
}),
|
||||
)
|
||||
// biome-ignore lint/suspicious/noAssignInExpressions: assign it intentially
|
||||
.addEventListener("load", () => (available.value = true));
|
||||
}
|
||||
});
|
||||
|
|
|
@ -153,7 +153,7 @@ const props = withDefaults(
|
|||
defineProps<{
|
||||
currentVisibility: NoteVisibility;
|
||||
currentLocalOnly: boolean;
|
||||
src?: HTMLElement;
|
||||
src?: HTMLElement | null;
|
||||
}>(),
|
||||
{},
|
||||
);
|
||||
|
|
|
@ -48,7 +48,7 @@ const id = os.getUniqueId();
|
|||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
modelValue: number;
|
||||
modelValue: number | null;
|
||||
disabled?: boolean;
|
||||
min: number;
|
||||
max: number;
|
||||
|
|
|
@ -75,29 +75,29 @@ const headerActions = computed(() =>
|
|||
icon: `${icon("ph-pencil")}`,
|
||||
text: i18n.ts.toEdit,
|
||||
handler: async (): Promise<void> => {
|
||||
const { canceled, result } = await os.form(clip.value.name, {
|
||||
const { canceled, result } = await os.form(clip.value!.name, {
|
||||
name: {
|
||||
type: "string",
|
||||
label: i18n.ts.name,
|
||||
default: clip.value.name,
|
||||
default: clip.value!.name,
|
||||
},
|
||||
description: {
|
||||
type: "string",
|
||||
required: false,
|
||||
multiline: true,
|
||||
label: i18n.ts.description,
|
||||
default: clip.value.description,
|
||||
default: clip.value!.description,
|
||||
},
|
||||
isPublic: {
|
||||
type: "boolean",
|
||||
label: i18n.ts.public,
|
||||
default: clip.value.isPublic,
|
||||
default: clip.value!.isPublic,
|
||||
},
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
os.apiWithDialog("clips/update", {
|
||||
clipId: clip.value.id,
|
||||
clipId: clip.value!.id,
|
||||
...result,
|
||||
});
|
||||
},
|
||||
|
|
|
@ -2,14 +2,15 @@ import { markRaw, ref } from "vue";
|
|||
import { isSignedIn } from "./me";
|
||||
import { Storage } from "./pizzax";
|
||||
import type { NoteVisibility } from "@/types/note";
|
||||
import type { entities, ApiTypes } from "firefish-js";
|
||||
|
||||
export const postFormActions: {
|
||||
title: string;
|
||||
handler: (note: entities.Note) => void | Promise<void>;
|
||||
handler: (from, update) => void | Promise<void>;
|
||||
}[] = [];
|
||||
export const userActions: {
|
||||
title: string;
|
||||
handler: (note: entities.Note) => void | Promise<void>;
|
||||
handler: (user: entities.User) => void | Promise<void>;
|
||||
}[] = [];
|
||||
export const noteActions: {
|
||||
title: string;
|
||||
|
@ -19,7 +20,7 @@ export const noteViewInterruptors: {
|
|||
handler: (note: entities.Note) => Promise<entities.Note>;
|
||||
}[] = [];
|
||||
export const notePostInterruptors: {
|
||||
handler: (note: entities.Note) => Promise<entities.Note>;
|
||||
handler: (note: ApiTypes.NoteSubmitReq) => Promise<ApiTypes.NoteSubmitReq>;
|
||||
}[] = [];
|
||||
|
||||
const menuOptions = [
|
||||
|
@ -466,7 +467,6 @@ import darkTheme from "@/themes/d-rosepine.json5";
|
|||
* Storage for configuration information that does not need to be constantly loaded into memory (non-reactive)
|
||||
*/
|
||||
import lightTheme from "@/themes/l-rosepinedawn.json5";
|
||||
import { entities } from "firefish-js";
|
||||
|
||||
export class ColdDeviceStorage {
|
||||
public static default = {
|
||||
|
|
12
packages/client/src/types/post-form.ts
Normal file
12
packages/client/src/types/post-form.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import type { entities } from "firefish-js";
|
||||
|
||||
export type PollType = {
|
||||
choices: string[];
|
||||
multiple: boolean;
|
||||
expiresAt: string | null;
|
||||
expiredAfter: number | null;
|
||||
};
|
||||
|
||||
export type NoteDraft = entities.Note & {
|
||||
poll?: PollType;
|
||||
};
|
|
@ -30,5 +30,5 @@
|
|||
"jsx": "preserve"
|
||||
},
|
||||
"compileOnSave": false,
|
||||
"include": ["./src/**/*.ts", "./src/**/*.vue"]
|
||||
"include": ["./src/**/*.ts", "./src/**/*.vue", "./@types"]
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@ import type {
|
|||
UserDetailed,
|
||||
UserGroup,
|
||||
UserList,
|
||||
UserLite,
|
||||
UserSorting,
|
||||
} from "./entities";
|
||||
|
||||
|
@ -46,11 +45,13 @@ type TODO = Record<string, any> | null;
|
|||
|
||||
type NoParams = Record<string, never>;
|
||||
|
||||
type ShowUserReq = { username: string; host?: string } | { userId: User["id"] };
|
||||
type ShowUserReq =
|
||||
| { username: string; host?: string | null }
|
||||
| { userId: User["id"] };
|
||||
|
||||
type NoteSubmitReq = {
|
||||
export type NoteSubmitReq = {
|
||||
editId?: null | Note["id"];
|
||||
visibility?: "public" | "home" | "followers" | "specified";
|
||||
visibility?: (typeof consts.noteVisibilities)[number];
|
||||
visibleUserIds?: User["id"][];
|
||||
text?: null | string;
|
||||
cw?: null | string;
|
||||
|
@ -62,10 +63,11 @@ type NoteSubmitReq = {
|
|||
channelId?: null | Channel["id"];
|
||||
poll?: null | {
|
||||
choices: string[];
|
||||
multiple?: boolean;
|
||||
expiresAt?: null | number;
|
||||
expiredAfter?: null | number;
|
||||
multiple: boolean;
|
||||
expiresAt: string | null;
|
||||
expiredAfter: number | null;
|
||||
};
|
||||
lang?: string;
|
||||
};
|
||||
|
||||
export type Endpoints = {
|
||||
|
|
|
@ -29,7 +29,7 @@ export type UserLite = {
|
|||
isIndexable: boolean;
|
||||
isCat?: boolean;
|
||||
speakAsCat?: boolean;
|
||||
driveCapacityOverrideMb: number | null,
|
||||
driveCapacityOverrideMb: number | null;
|
||||
};
|
||||
|
||||
export type UserDetailed = UserLite & {
|
||||
|
@ -238,8 +238,8 @@ export interface RenoteNotification extends BaseNotification {
|
|||
user: User;
|
||||
userId: User["id"];
|
||||
note: Note & {
|
||||
renote: Note,
|
||||
renoteId: string,
|
||||
renote: Note;
|
||||
renoteId: string;
|
||||
};
|
||||
}
|
||||
export interface QuoteNotification extends BaseNotification {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import * as acct from "./acct";
|
||||
import type { Acct } from "./acct";
|
||||
import { Endpoints } from "./api.types";
|
||||
import type * as ApiTypes from "./api.types";
|
||||
import * as consts from "./consts";
|
||||
import Stream, { Connection } from "./streaming";
|
||||
import * as StreamTypes from "./streaming.types";
|
||||
|
@ -8,6 +9,7 @@ import type * as TypeUtils from "./type-utils";
|
|||
|
||||
export {
|
||||
Endpoints,
|
||||
type ApiTypes,
|
||||
Stream,
|
||||
Connection as ChannelConnection,
|
||||
StreamTypes,
|
||||
|
|
Loading…
Reference in a new issue