From ff3a0eb0c94c942aab3d7c9c0c586845c7444f0e Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Tue, 24 Jun 2025 18:29:17 +0900
Subject: [PATCH] wip
---
locales/index.d.ts | 8 +
locales/ja-JP.yml | 2 +
.../frontend/src/components/MkPostForm.vue | 147 ++++++++++--------
.../src/components/MkPostFormDialog.vue | 8 +-
4 files changed, 94 insertions(+), 71 deletions(-)
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 0d8f42823e..1a8d74e233 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -12279,6 +12279,14 @@ export interface Locale extends ILocale {
* {channel}への投稿
*/
"postTo": ParameterizedString<"channel">;
+ /**
+ * 下書きへ保存
+ */
+ "save": string;
+ /**
+ * 下書きから復元
+ */
+ "restore": string;
};
}
declare const locales: {
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 47ffbf0a94..69c2406930 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -3289,3 +3289,5 @@ _drafts:
replyTo: "{user}への返信"
quoteOf: "{user}のノートへの引用"
postTo: "{channel}への投稿"
+ save: "下書きへ保存"
+ restore: "下書きから復元"
diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue
index bb96cebb38..a82f55195b 100644
--- a/packages/frontend/src/components/MkPostForm.vue
+++ b/packages/frontend/src/components/MkPostForm.vue
@@ -17,6 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only
+
@@ -90,7 +91,6 @@ SPDX-License-Identifier: AGPL-3.0-only
-
@@ -1071,18 +1071,8 @@ async function handleSavingServerDraft(ev?: Event) {
}
}
-async function esc(ev: Event) {
- const { canClosePostForm } = await handleSavingServerDraft(ev);
- if (canClosePostForm) {
- emit('esc');
- }
-}
-
-async function cancel() {
- const { canClosePostForm } = await handleSavingServerDraft();
- if (canClosePostForm) {
- emit('cancel');
- }
+function cancel() {
+ emit('cancel');
}
function insertMention() {
@@ -1190,52 +1180,70 @@ function getNoteDraftDialog(): Promise {
});
}
-function showDraftMenu() {
- getNoteDraftDialog().then(draft => {
- if (draft == null) return;
+function showDraftMenu(ev: MouseEvent) {
+ function showDraftSelectDialog() {
+ getNoteDraftDialog().then(draft => {
+ if (draft == null) return;
- text.value = draft.text ?? '';
- useCw.value = draft.cw != null;
- cw.value = draft.cw ?? null;
- visibility.value = draft.visibility;
- localOnly.value = draft.localOnly ?? false;
- files.value = draft.files ?? [];
- hashtags.value = draft.hashtag ?? '';
- if (draft.hashtag) withHashtags.value = true;
- if (draft.poll) {
+ text.value = draft.text ?? '';
+ useCw.value = draft.cw != null;
+ cw.value = draft.cw ?? null;
+ visibility.value = draft.visibility;
+ localOnly.value = draft.localOnly ?? false;
+ files.value = draft.files ?? [];
+ hashtags.value = draft.hashtag ?? '';
+ if (draft.hashtag) withHashtags.value = true;
+ if (draft.poll) {
// 投票を一時的に空にしないと反映されないため
- poll.value = null;
- nextTick(() => {
- poll.value = {
- choices: draft.poll!.choices,
- multiple: draft.poll!.multiple,
- expiresAt: draft.poll!.expiresAt ? (new Date(draft.poll!.expiresAt)).getTime() : null,
- expiredAfter: null,
- };
- });
- }
- if (draft.visibleUserIds) {
- misskeyApi('users/show', { userIds: draft.visibleUserIds }).then(users => {
- users.forEach(u => pushVisibleUser(u));
- });
- }
- quoteId.value = draft.renoteId ?? null;
- renoteTargetNote.value = draft.renote;
- replyTargetNote.value = draft.reply;
- reactionAcceptance.value = draft.reactionAcceptance;
- if (draft.channel) targetChannel.value = draft.channel as unknown as Misskey.entities.Channel;
-
- visibleUsers.value = [];
- draft.visibleUserIds?.forEach(uid => {
- if (!visibleUsers.value.some(u => u.id === uid)) {
- misskeyApi('users/show', { userId: uid }).then(user => {
- pushVisibleUser(user);
+ poll.value = null;
+ nextTick(() => {
+ poll.value = {
+ choices: draft.poll!.choices,
+ multiple: draft.poll!.multiple,
+ expiresAt: draft.poll!.expiresAt ? (new Date(draft.poll!.expiresAt)).getTime() : null,
+ expiredAfter: null,
+ };
});
}
- });
+ if (draft.visibleUserIds) {
+ misskeyApi('users/show', { userIds: draft.visibleUserIds }).then(users => {
+ users.forEach(u => pushVisibleUser(u));
+ });
+ }
+ quoteId.value = draft.renoteId ?? null;
+ renoteTargetNote.value = draft.renote;
+ replyTargetNote.value = draft.reply;
+ reactionAcceptance.value = draft.reactionAcceptance;
+ if (draft.channel) targetChannel.value = draft.channel as unknown as Misskey.entities.Channel;
- serverDraftId.value = draft.id;
- });
+ visibleUsers.value = [];
+ draft.visibleUserIds?.forEach(uid => {
+ if (!visibleUsers.value.some(u => u.id === uid)) {
+ misskeyApi('users/show', { userId: uid }).then(user => {
+ pushVisibleUser(user);
+ });
+ }
+ });
+
+ serverDraftId.value = draft.id;
+ });
+ }
+
+ os.popupMenu([{
+ type: 'button',
+ text: i18n.ts._drafts.save,
+ icon: 'ti ti-cloud-upload',
+ action: async () => {
+ saveServerDraft();
+ },
+ }, {
+ type: 'button',
+ text: i18n.ts._drafts.restore,
+ icon: 'ti ti-cloud-download',
+ action: () => {
+ showDraftSelectDialog();
+ },
+ }], (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined);
}
onMounted(() => {
@@ -1323,8 +1331,6 @@ async function canClose() {
defineExpose({
clear,
canClose,
- onEsc: esc,
- onCancel: cancel,
});
@@ -1352,21 +1358,18 @@ defineExpose({
.headerLeft {
display: flex;
- flex: 0 1 100px;
+ flex: 1;
+ flex-wrap: nowrap;
+ align-items: center;
+ gap: 6px;
+ padding-left: 12px;
}
.cancel {
- padding: 0;
- font-size: 1em;
- height: 100%;
- flex: 0 1 50px;
+ padding: 8px;
}
.account {
- height: 100%;
- display: inline-flex;
- vertical-align: bottom;
- flex: 0 1 50px;
}
.avatar {
@@ -1375,6 +1378,20 @@ defineExpose({
margin: auto;
}
+.draftButton {
+ padding: 8px;
+ font-size: 90%;
+ border-radius: 6px;
+
+ &:hover {
+ background: light-dark(rgba(0, 0, 0, 0.05), rgba(255, 255, 255, 0.05));
+ }
+
+ &:disabled {
+ background: none;
+ }
+}
+
.headerRight {
display: flex;
min-height: 48px;
diff --git a/packages/frontend/src/components/MkPostFormDialog.vue b/packages/frontend/src/components/MkPostFormDialog.vue
index 5753ec00db..1f7796bd83 100644
--- a/packages/frontend/src/components/MkPostFormDialog.vue
+++ b/packages/frontend/src/components/MkPostFormDialog.vue
@@ -58,15 +58,11 @@ async function _close() {
}
function onEsc(ev: KeyboardEvent) {
- // PostForm側で下書き保存確認を行う
- // 実際のclose処理はPostForm側のesc emitから
- form.value?.onEsc(ev);
+ _close();
}
function onBgClick() {
- // PostForm側で下書き保存確認を行う
- // 実際のclose処理はPostForm側のcancel emitから
- form.value?.onCancel();
+ _close();
}
function onModalClosed() {