hippofish/packages/client/src/pages/share.vue

197 lines
4.7 KiB
Vue
Raw Normal View History

2020-02-06 15:12:27 +01:00
<template>
2023-04-08 02:01:42 +02:00
<MkStickyContainer>
<template #header
><MkPageHeader :actions="headerActions" :tabs="headerTabs"
/></template>
<MkSpacer :content-max="800">
<XPostForm
v-if="state === 'writing'"
fixed
:instant="true"
:initial-text="initialText"
:initial-visibility="visibility"
:initial-files="files"
:initial-local-only="localOnly"
:reply="reply"
:renote="renote"
:initial-visible-users="visibleUsers"
class="_panel"
@posted="state = 'posted'"
/>
<MkButton
v-else-if="state === 'posted'"
primary
class="close"
@click="close()"
>{{ i18n.ts.close }}</MkButton
>
</MkSpacer>
</MkStickyContainer>
2020-02-06 15:12:27 +01:00
</template>
<script lang="ts" setup>
2023-09-02 01:27:33 +02:00
import { computed, ref } from "vue";
// SPECIFICATION: https://misskey-hub.net/docs/features/share-form.html
2024-03-02 06:24:05 +01:00
import type { entities } from "firefish-js";
import { acct, noteVisibilities } from "firefish-js";
2023-04-08 02:01:42 +02:00
import MkButton from "@/components/MkButton.vue";
import XPostForm from "@/components/MkPostForm.vue";
import * as os from "@/os";
import { mainRouter } from "@/router";
import { definePageMetadata } from "@/scripts/page-metadata";
import { i18n } from "@/i18n";
import icon from "@/scripts/icon";
const urlParams = new URLSearchParams(window.location.search);
2023-04-08 02:01:42 +02:00
const localOnlyQuery = urlParams.get("localOnly");
const visibilityQuery = urlParams.get("visibility");
const state = ref("fetching" as "fetching" | "writing" | "posted");
const title = ref(urlParams.get("title"));
2023-04-08 02:01:42 +02:00
const text = urlParams.get("text");
const url = urlParams.get("url");
const initialText = ref(null as string | null);
const reply = ref(null as entities.Note | null);
const renote = ref(null as entities.Note | null);
const visibility = ref(
2023-07-06 03:28:27 +02:00
noteVisibilities.includes(visibilityQuery) ? visibilityQuery : null,
2023-04-08 02:01:42 +02:00
);
const localOnly = ref(
2023-07-06 03:28:27 +02:00
localOnlyQuery === "0" ? false : localOnlyQuery === "1" ? true : null,
2023-04-08 02:01:42 +02:00
);
const files = ref([] as entities.DriveFile[]);
const visibleUsers = ref([] as entities.User[]);
async function init() {
2023-04-08 02:01:42 +02:00
let noteText = "";
if (title.value) noteText += `${title.value}\n`;
// Googleニュース対策
if (text?.startsWith(`${title.value}.\n`))
noteText += text.replace(`${title.value}.\n`, "");
else if (text && title.value !== text) noteText += `${text}\n`;
if (url) noteText += `${url}`;
initialText.value = noteText.trim();
if (visibility.value === "specified") {
2023-04-08 02:01:42 +02:00
const visibleUserIds = urlParams.get("visibleUserIds");
const visibleAccts = urlParams.get("visibleAccts");
await Promise.all(
[
2023-04-08 02:01:42 +02:00
...(visibleUserIds
? visibleUserIds.split(",").map((userId) => ({ userId }))
: []),
2024-03-28 17:26:52 +01:00
...(visibleAccts ? visibleAccts.split(",").map(acct.parse) : []),
]
2023-04-08 02:01:42 +02:00
// TypeScriptの指示通りに変換する
.map((q) =>
"username" in q
? {
username: q.username,
host: q.host === null ? undefined : q.host,
2024-02-11 18:50:57 +01:00
}
2023-07-06 03:28:27 +02:00
: q,
2023-04-08 02:01:42 +02:00
)
.map((q) =>
os.api("users/show", q).then(
(user) => {
visibleUsers.value.push(user);
2023-04-08 02:01:42 +02:00
},
() => {
2024-03-28 17:26:52 +01:00
console.error(`Invalid user query: ${JSON.stringify(q)}`);
2023-07-06 03:28:27 +02:00
},
),
),
);
}
2020-02-06 15:12:27 +01:00
try {
2023-09-02 01:27:33 +02:00
// #region Reply
2023-04-08 02:01:42 +02:00
const replyId = urlParams.get("replyId");
const replyUri = urlParams.get("replyUri");
if (replyId) {
reply.value = await os.api("notes/show", {
noteId: replyId,
});
} else if (replyUri) {
2023-04-08 02:01:42 +02:00
const obj = await os.api("ap/show", {
uri: replyUri,
});
2023-04-08 02:01:42 +02:00
if (obj.type === "Note") {
reply.value = obj.object;
}
}
2023-09-02 01:27:33 +02:00
// #endregion
2023-09-02 01:27:33 +02:00
// #region Renote
2023-04-08 02:01:42 +02:00
const renoteId = urlParams.get("renoteId");
const renoteUri = urlParams.get("renoteUri");
if (renoteId) {
renote.value = await os.api("notes/show", {
noteId: renoteId,
});
} else if (renoteUri) {
2023-04-08 02:01:42 +02:00
const obj = await os.api("ap/show", {
uri: renoteUri,
});
2023-04-08 02:01:42 +02:00
if (obj.type === "Note") {
renote.value = obj.object;
}
}
2023-09-02 01:27:33 +02:00
// #endregion
2023-09-02 01:27:33 +02:00
// #region Drive files
2023-04-08 02:01:42 +02:00
const fileIds = urlParams.get("fileIds");
if (fileIds) {
await Promise.all(
2023-04-08 02:01:42 +02:00
fileIds.split(",").map((fileId) =>
os.api("drive/files/show", { fileId }).then(
(file) => {
files.value.push(file);
2023-04-08 02:01:42 +02:00
},
() => {
console.error(`Failed to fetch a file ${fileId}`);
2023-07-06 03:28:27 +02:00
},
),
),
);
}
2023-09-02 01:27:33 +02:00
// #endregion
} catch (err) {
os.alert({
2023-04-08 02:01:42 +02:00
type: "error",
title: err.message,
text: err.name,
});
}
state.value = "writing";
}
init();
2020-02-06 15:12:27 +01:00
function close(): void {
window.close();
// 閉じなければ100ms後タイムラインに
window.setTimeout(() => {
2023-04-08 02:01:42 +02:00
mainRouter.push("/");
}, 100);
}
const headerActions = computed(() => []);
const headerTabs = computed(() => []);
definePageMetadata({
title: i18n.ts.share,
icon: `${icon("ph-share-network")}`,
2020-02-06 15:12:27 +01:00
});
</script>
<style lang="scss" scoped>
.close {
margin: 16px auto;
}
2020-02-06 15:12:27 +01:00
</style>