Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
-

### Client
-
- Enhance: 投稿フォームの下書き・予約投稿のメニューを整理
- 投稿フォーム左上からアクセスできた、下書き・予約投稿の一覧ボタンは、右上の「…」メニュー内に移動しました

### Server
-
Expand Down
4 changes: 3 additions & 1 deletion locales/ja-JP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1330,6 +1330,7 @@ federationSpecified: "このサーバーはホワイトリスト連合で運用
federationDisabled: "このサーバーは連合が無効化されています。他のサーバーのユーザーとやり取りすることはできません。"
draft: "下書き"
draftsAndScheduledNotes: "下書きと予約投稿"
scheduledNotes: "予約投稿"
confirmOnReact: "リアクションする際に確認する"
reactAreYouSure: "\" {emoji} \" をリアクションしますか?"
markAsSensitiveConfirm: "このメディアをセンシティブとして設定しますか?"
Expand Down Expand Up @@ -2695,14 +2696,15 @@ _postForm:
replyPlaceholder: "このノートに返信..."
quotePlaceholder: "このノートを引用..."
channelPlaceholder: "チャンネルに投稿..."
postAccount: "投稿するアカウント"
showHowToUse: "フォームの説明を表示"
_howToUse:
content_title: "本文"
content_description: "投稿する内容を入力します。"
toolbar_title: "ツールバー"
toolbar_description: "ファイルやアンケートの添付、注釈やハッシュタグの設定、絵文字やメンションの挿入などが行えます。"
account_title: "アカウントメニュー"
account_description: "投稿するアカウントを切り替えたり、アカウントに保存した下書き・予約投稿を一覧できます。"
account_description: "投稿するアカウントを切り替えることができます。"
visibility_title: "公開範囲"
visibility_description: "ノートを公開する範囲の設定が行えます。"
menu_title: "メニュー"
Expand Down
191 changes: 102 additions & 89 deletions packages/frontend/src/components/MkPostForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,63 @@ function showOtherSettings() {
break;
}

function showDraftsDialog(scheduled: boolean) {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkNoteDraftsDialog.vue')), {
scheduled,
}, {
restore: async (draft: Misskey.entities.NoteDraft) => {
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;
scheduledAt.value = draft.scheduledAt ?? null;
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);
});
}
});

serverDraftId.value = draft.id;
},
cancel: () => {

},
closed: () => {
dispose();
},
});
}

const menuItems = [{
type: 'component',
component: XTextCounter,
Expand All @@ -650,25 +707,49 @@ function showOtherSettings() {
toggleReactionAcceptance();
},
}, { type: 'divider' }, {
type: 'button',
text: i18n.ts._drafts.saveToDraft,
icon: 'ti ti-cloud-upload',
action: async () => {
if (!canSaveAsServerDraft.value) {
return os.alert({
type: 'error',
text: i18n.ts._drafts.cannotCreateDraft,
});
}
saveServerDraft();
},
}, ...($i.policies.scheduledNoteLimit > 0 ? [{
type: 'parent',
icon: 'ti ti-cloud',
text: i18n.ts.drafts,
children: [{
type: 'button',
text: i18n.ts._drafts.listDrafts,
icon: 'ti ti-cloud-download',
action: () => {
showDraftsDialog(false);
},
}, {
type: 'button',
text: i18n.ts._drafts.saveToDraft,
icon: 'ti ti-cloud-upload',
action: async () => {
if (!canSaveAsServerDraft.value) {
return os.alert({
type: 'error',
text: i18n.ts._drafts.cannotCreateDraft,
});
}
saveServerDraft();
},
}],
}, {
type: 'parent',
icon: 'ti ti-calendar-time',
text: i18n.ts.schedulePost + '...',
action: () => {
schedule();
},
}] : []), { type: 'divider' }, {
text: i18n.ts.scheduledNotes,
children: [{
type: 'button',
text: i18n.ts._drafts.listScheduledNotes,
icon: 'ti ti-clock-down',
action: () => {
showDraftsDialog(true);
},
}, ...($i.policies.scheduledNoteLimit > 0 ? [{
icon: 'ti ti-calendar-time',
text: i18n.ts.schedulePost,
action: () => {
schedule();
},
}] : [])],
}, { type: 'divider' }, {
type: 'switch',
icon: 'ti ti-eye',
text: i18n.ts.preview,
Expand Down Expand Up @@ -1253,63 +1334,6 @@ const postAccount = ref<Misskey.entities.UserDetailed | null>(null);
async function openAccountMenu(ev: PointerEvent) {
if (props.mock) return;

function showDraftsDialog(scheduled: boolean) {
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkNoteDraftsDialog.vue')), {
scheduled,
}, {
restore: async (draft: Misskey.entities.NoteDraft) => {
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;
scheduledAt.value = draft.scheduledAt ?? null;
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);
});
}
});

serverDraftId.value = draft.id;
},
cancel: () => {

},
closed: () => {
dispose();
},
});
}

const items = await getAccountMenu({
withExtraOperation: false,
includeCurrentAccount: true,
Expand All @@ -1324,20 +1348,9 @@ async function openAccountMenu(ev: PointerEvent) {
});

os.popupMenu([{
type: 'button',
text: i18n.ts._drafts.listDrafts,
icon: 'ti ti-cloud-download',
action: () => {
showDraftsDialog(false);
},
}, {
type: 'button',
text: i18n.ts._drafts.listScheduledNotes,
icon: 'ti ti-clock-down',
action: () => {
showDraftsDialog(true);
},
}, { type: 'divider' }, ...items], (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined);
type: 'label',
text: i18n.ts._postForm.postAccount,
}, ...items], (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined);
}

function showPerUploadItemMenu(item: UploaderItem, ev: PointerEvent) {
Expand Down
10 changes: 9 additions & 1 deletion packages/i18n/src/autogen/locale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5332,6 +5332,10 @@ export interface Locale extends ILocale {
* 下書きと予約投稿
*/
"draftsAndScheduledNotes": string;
/**
* 予約投稿
*/
"scheduledNotes": string;
/**
* リアクションする際に確認する
*/
Expand Down Expand Up @@ -10222,6 +10226,10 @@ export interface Locale extends ILocale {
* チャンネルに投稿...
*/
"channelPlaceholder": string;
/**
* 投稿するアカウント
*/
"postAccount": string;
/**
* フォームの説明を表示
*/
Expand All @@ -10248,7 +10256,7 @@ export interface Locale extends ILocale {
*/
"account_title": string;
/**
* 投稿するアカウントを切り替えたり、アカウントに保存した下書き・予約投稿を一覧できます
* 投稿するアカウントを切り替えることができます
*/
"account_description": string;
/**
Expand Down
Loading