diff --git a/CHANGELOG.md b/CHANGELOG.md index dbc519f32d..4e4149f10f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ - Enhance: プラグインを削除した際には、使用されていたアクセストークンも同時に削除されるようになりました - Enhance: プラグインで`Plugin:register_note_view_interruptor`を用いてnoteの代わりにnullを返却することでノートを非表示にできるようになりました - Enhance: AiScript関数`Mk:nyaize()`が追加されました +- Enhance: 情報→ツール はナビゲーションバーにツールとして独立した項目になりました - Enhance: その他細かなブラッシュアップ - Fix: 投稿フォームでのユーザー変更がプレビューに反映されない問題を修正 - Fix: ユーザーページの ノート > ファイル付き タブにリプライが表示されてしまう diff --git a/packages/frontend/src/navbar.ts b/packages/frontend/src/navbar.ts index 7f182a98f7..e72a4dc316 100644 --- a/packages/frontend/src/navbar.ts +++ b/packages/frontend/src/navbar.ts @@ -6,7 +6,7 @@ import { computed, reactive } from 'vue'; import { $i } from '@/account.js'; import { miLocalStorage } from '@/local-storage.js'; -import { openInstanceMenu } from '@/ui/_common_/common.js'; +import { openInstanceMenu, openToolsMenu } from '@/ui/_common_/common.js'; import { lookup } from '@/scripts/lookup.js'; import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; @@ -142,6 +142,13 @@ export const navbarItemDef = reactive({ openInstanceMenu(ev); }, }, + tools: { + title: i18n.ts.tools, + icon: 'ti ti-tool', + action: (ev) => { + openToolsMenu(ev); + }, + }, reload: { title: i18n.ts.reload, icon: 'ti ti-refresh', diff --git a/packages/frontend/src/pages/timeline.vue b/packages/frontend/src/pages/timeline.vue index 159e1d633d..cfe270aefb 100644 --- a/packages/frontend/src/pages/timeline.vue +++ b/packages/frontend/src/pages/timeline.vue @@ -148,36 +148,42 @@ function closeTutorial(): void { defaultStore.set('timelineTutorials', before); } -const headerActions = $computed(() => [ - ...[deviceKind === 'desktop' ? { - icon: 'ti ti-refresh', - text: i18n.ts.reload, - handler: (ev) => { - console.log('called'); - tlComponent.reloadTimeline(); +const headerActions = $computed(() => { + const tmp = [ + { + icon: 'ti ti-dots', + text: i18n.ts.options, + handler: (ev) => { + os.popupMenu([{ + type: 'switch', + text: i18n.ts.showRenotes, + icon: 'ti ti-repeat', + ref: $$(withRenotes), + }, src === 'local' || src === 'social' ? { + type: 'switch', + text: i18n.ts.showRepliesToOthersInTimeline, + ref: $$(withReplies), + } : undefined, { + type: 'switch', + text: i18n.ts.fileAttachedOnly, + icon: 'ti ti-photo', + ref: $$(onlyFiles), + }], ev.currentTarget ?? ev.target); + }, }, - } : {}], { - icon: 'ti ti-dots', - text: i18n.ts.options, - handler: (ev) => { - os.popupMenu([{ - type: 'switch', - text: i18n.ts.showRenotes, - icon: 'ti ti-repeat', - ref: $$(withRenotes), - }, src === 'local' || src === 'social' ? { - type: 'switch', - text: i18n.ts.showRepliesToOthersInTimeline, - ref: $$(withReplies), - } : undefined, { - type: 'switch', - text: i18n.ts.fileAttachedOnly, - icon: 'ti ti-photo', - ref: $$(onlyFiles), - }], ev.currentTarget ?? ev.target); - }, - }, -]); + ]; + if (deviceKind === 'desktop') { + tmp.unshift({ + icon: 'ti ti-refresh', + text: i18n.ts.reload, + handler: (ev: Event) => { + console.log('called'); + tlComponent.reloadTimeline(); + }, + }); + } + return tmp; +}); const headerTabs = $computed(() => [...(defaultStore.reactiveState.pinnedUserLists.value.map(l => ({ key: 'list:' + l.id, diff --git a/packages/frontend/src/ui/_common_/common.ts b/packages/frontend/src/ui/_common_/common.ts index 9ffa5b95b5..64008c5748 100644 --- a/packages/frontend/src/ui/_common_/common.ts +++ b/packages/frontend/src/ui/_common_/common.ts @@ -4,12 +4,42 @@ */ import { defineAsyncComponent } from 'vue'; +import type { MenuItem } from '@/types/menu.js'; import * as os from '@/os.js'; import { instance } from '@/instance.js'; import { host } from '@/config.js'; import { i18n } from '@/i18n.js'; import { $i } from '@/account.js'; +function toolsMenuItems(): MenuItem[] { + return [{ + type: 'link', + to: '/scratchpad', + text: i18n.ts.scratchpad, + icon: 'ti ti-terminal-2', + }, { + type: 'link', + to: '/api-console', + text: 'API Console', + icon: 'ti ti-terminal-2', + }, { + type: 'link', + to: '/clicker', + text: '🍪👈', + icon: 'ti ti-cookie', + }, ($i && ($i.isAdmin || $i.policies.canManageCustomEmojis)) ? { + type: 'link', + to: '/custom-emojis-manager', + text: i18n.ts.manageCustomEmojis, + icon: 'ti ti-icons', + } : undefined, ($i && ($i.isAdmin || $i.policies.canManageAvatarDecorations)) ? { + type: 'link', + to: '/avatar-decorations', + text: i18n.ts.manageAvatarDecorations, + icon: 'ti ti-sparkles', + } : undefined]; +} + export function openInstanceMenu(ev: MouseEvent) { os.popupMenu([{ text: instance.name ?? host, @@ -48,32 +78,7 @@ export function openInstanceMenu(ev: MouseEvent) { type: 'parent', text: i18n.ts.tools, icon: 'ti ti-tool', - children: [{ - type: 'link', - to: '/scratchpad', - text: i18n.ts.scratchpad, - icon: 'ti ti-terminal-2', - }, { - type: 'link', - to: '/api-console', - text: 'API Console', - icon: 'ti ti-terminal-2', - }, { - type: 'link', - to: '/clicker', - text: '🍪👈', - icon: 'ti ti-cookie', - }, ($i && ($i.isAdmin || $i.policies.canManageCustomEmojis)) ? { - type: 'link', - to: '/custom-emojis-manager', - text: i18n.ts.manageCustomEmojis, - icon: 'ti ti-icons', - } : undefined, ($i && ($i.isAdmin || $i.policies.canManageAvatarDecorations)) ? { - type: 'link', - to: '/avatar-decorations', - text: i18n.ts.manageAvatarDecorations, - icon: 'ti ti-sparkles', - } : undefined], + children: toolsMenuItems(), }, null, (instance.impressumUrl) ? { text: i18n.ts.impressum, icon: 'ti ti-file-invoice', @@ -112,3 +117,9 @@ export function openInstanceMenu(ev: MouseEvent) { align: 'left', }); } + +export function openToolsMenu(ev: MouseEvent) { + os.popupMenu(toolsMenuItems(), ev.currentTarget ?? ev.target, { + align: 'left', + }); +}