Skip to content

Commit

Permalink
Merge pull request #562
Browse files Browse the repository at this point in the history
* feat: キーボードショートカット一覧

* chore: キーボードショートカットの表示をhから?に

* refactor: fix locale and missing hotkeys

* enhance: navbarからアクセスできるように
  • Loading branch information
1673beta authored Feb 1, 2025
1 parent 7cfe915 commit e746616
Show file tree
Hide file tree
Showing 9 changed files with 286 additions and 2 deletions.
17 changes: 17 additions & 0 deletions locales/en-US.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1467,6 +1467,7 @@ translateProfile: "Translate profile"
trustedLinkUrlPatterns: "Link to external site warning exclusion list"
trustedLinkUrlPatternsDescription: "Separate with spaces for an AND condition or with line breaks for an OR condition. Using surrounding keywords with slashes will turn them into a regular expression. If you write only the domain name, it will be a backward match."
open: "Open"
keyboardShortcuts: "Keyboard shortcuts"
_nsfwOpenBehavior:
click: "Click to open"
doubleClick: "Double click to open"
Expand Down Expand Up @@ -3286,3 +3287,19 @@ _accountTruncate:
requestAccountDelete: "Request account truncation"
started: "Truncation has been started."
inProgress: "Truncation is currently in progress"
_keyboardShortCut:
title: "Keyboard shortcuts"
description: "List of keyboard shortcuts available in Web client."
list: "List of keyboard shortcuts"
_category:
general: "General"
postForm: "Post form"
_general:
openPostForm: "Open Post Form"
toggleDarkMode: "Toggle Dark Mode"
redirectToSearch: "Redirect to search page"
_postForm:
toggleVisibility: "Toggle Visibility"
toggleLocalOnly: "Toggle Local Only"
featureWarn: "This feature is available when enable settings in \"Settings - CherryPick\"."
sendPost: "Post note"
60 changes: 60 additions & 0 deletions locales/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5898,6 +5898,10 @@ export interface Locale extends ILocale {
* 開く
*/
"open": string;
/**
* キーボードショートカット
*/
"keyboardShortcuts": string;
"_nsfwOpenBehavior": {
/**
* タップして開く
Expand Down Expand Up @@ -12718,6 +12722,62 @@ export interface Locale extends ILocale {
*/
"inProgress": string;
};
"_keyboardShortCut": {
/**
* キーボードショートカット
*/
"title": string;
/**
* Web上で使えるキーボードショートカットの一覧です。
*/
"description": string;
/**
* ショートカット一覧
*/
"list": string;
"_category": {
/**
* 一般
*/
"general": string;
/**
* 投稿フォーム
*/
"postForm": string;
};
"_general": {
/**
* 投稿フォームを開く
*/
"openPostForm": string;
/**
* ダークモードを切り替える
*/
"toggleDarkMode": string;
/**
* 検索ページに移動
*/
"redirectToSearch": string;
};
"_postForm": {
/**
* 公開範囲を切り替える
*/
"toggleVisibility": string;
/**
* 連合なしを切り替える
*/
"toggleLocalOnly": string;
/**
* この機能は設定>CherryPickから該当の機能を有効にすることで利用できます。
*/
"featureWarn": string;
/**
* 投稿する
*/
"sendPost": string;
};
};
}
declare const locales: {
[lang: string]: Locale;
Expand Down
18 changes: 18 additions & 0 deletions locales/ja-JP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1467,6 +1467,7 @@ translateProfile: "プロフィールを翻訳する"
trustedLinkUrlPatterns: "外部サイトへのリンク警告 除外リスト"
trustedLinkUrlPatternsDescription: "スペースで区切るとAND指定になり、改行で区切るとOR指定になります。スラッシュで囲むと正規表現になります。ドメイン名だけ書くと後方一致になります。"
open: "開く"
keyboardShortcuts: "キーボードショートカット"

_nsfwOpenBehavior:
click: "タップして開く"
Expand Down Expand Up @@ -3400,3 +3401,20 @@ _accountTruncate:
requestAccountTruncate: "アカウント整理をリクエスト"
started: "整理処理が開始されました。"
inProgress: "整理が進行中"

_keyboardShortCut:
title: "キーボードショートカット"
description: "Web上で使えるキーボードショートカットの一覧です。"
list: "ショートカット一覧"
_category:
general: "一般"
postForm: "投稿フォーム"
_general:
openPostForm: "投稿フォームを開く"
toggleDarkMode: "ダークモードを切り替える"
redirectToSearch: "検索ページに移動"
_postForm:
toggleVisibility: "公開範囲を切り替える"
toggleLocalOnly: "連合なしを切り替える"
featureWarn: "この機能は設定>CherryPickから該当の機能を有効にすることで利用できます。"
sendPost: "投稿する"
9 changes: 7 additions & 2 deletions packages/frontend/src/boot/main-boot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { type Keymap, makeHotkey } from '@/scripts/hotkey.js';
import { addCustomEmoji, removeCustomEmojis, updateCustomEmojis } from '@/custom-emojis.js';
import { userName } from '@/filters/user.js';
import { vibrate } from '@/scripts/vibrate.js';
import * as os from '@/os.js';

export async function mainBoot() {
const { isClientUpdated, isClientMigrated } = await common(() => {
Expand Down Expand Up @@ -392,11 +393,11 @@ export async function mainBoot() {
});

main.on('readAllMessagingMessages', () => {
updateAccount({ hasUnreadMessagingMessage: false });
updateAccountPartial({ hasUnreadMessagingMessage: false });
});

main.on('unreadMessagingMessage', () => {
updateAccount({ hasUnreadMessagingMessage: true });
updateAccountPartial({ hasUnreadMessagingMessage: true });
sound.playMisskeySfx('chatBg');
vibrate(defaultStore.state.vibrateChatBg ? [50, 40] : []);
});
Expand Down Expand Up @@ -436,6 +437,10 @@ export async function mainBoot() {
's': () => {
mainRouter.push('/search');
},
// 環境によるかもしれないが?では反応しないため、shift+/にする必要がある
'shift+/': () => {
os.popup(defineAsyncComponent(() => import('@/components/MkKeyboardShortcut.vue')), {}, {});
},
} as const satisfies Keymap;
document.addEventListener('keydown', makeHotkey(keymap), { passive: false });

Expand Down
37 changes: 37 additions & 0 deletions packages/frontend/src/components/MkKeyboardShortcut.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<!--
SPDX-FileCopyrightText: syuilo and misskey-project & noridev and cherrypick-project
SPDX-License-Identifier: AGPL-3.0-only
-->

<template>
<MkModalWindow
ref="dialog"
:width="600"
:height="500"
@close="cancel()"
@closed="emit('closed')"
>
<template #header>{{ i18n.ts._keyboardShortCut.title }}</template>
<XKeyBoardShortcut :popup="true" style="background: var(--MI_THEME-bg)"/>
</MkModalWindow>
</template>

<script lang="ts" setup>
import { shallowRef } from 'vue';
import MkModalWindow from '@/components/MkModalWindow.vue';
import XKeyBoardShortcut from '@/pages/keyboard-shortcut.vue';
import { i18n } from '@/i18n.js';

const emit = defineEmits<{
(ev: 'done'): void;
(ev: 'closed'): void;
}>();

const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();

function cancel() {
emit('done');
dialog.value?.close();
}

</script>
5 changes: 5 additions & 0 deletions packages/frontend/src/navbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,11 @@ export const navbarItemDef = reactive({
text: i18n.ts._mfc.cheatSheet,
icon: 'ti ti-help-circle',
to: '/mfc-cheat-sheet',
}, {
type: 'link',
text: i18n.ts._keyboardShortCut.list,
icon: 'ti ti-keyboard',
to: '/keyboard-shortcuts',
}], ev.currentTarget ?? ev.target);
},
},
Expand Down
138 changes: 138 additions & 0 deletions packages/frontend/src/pages/keyboard-shortcut.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<!--
SPDX-FileCopyrightText: syuilo and misskey-project & noridev and cherrypick-project
SPDX-License-Identifier: AGPL-3.0-only
-->

<template>
<MkStickyContainer>
<template #header><MkPageHeader v-if="!popup" :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="800">
<div :class="$style.root">
<div :class="$style.intro">{{ i18n.ts._keyboardShortCut.description }}</div>
<MkFoldableSection>
<template #header>{{ i18n.ts._keyboardShortCut._category.general }}</template>
<div :class="$style.section">
<div :class="$style.title">{{ i18n.ts._keyboardShortCut._general.openPostForm }}</div>
<div :class="$style.content">
<kbd>N</kbd>, <kbd>P</kbd>
</div>
</div>
<div :class="$style.section">
<div :class="$style.title">{{ i18n.ts._keyboardShortCut._general.toggleDarkMode }}</div>
<div :class="$style.content">
<kbd>D</kbd>
</div>
</div>
<div :class="$style.section">
<div :class="$style.title">{{ i18n.ts._keyboardShortCut._general.redirectToSearch }}</div>
<div :class="$style.content">
<kbd>S</kbd>
</div>
</div>
</MkFoldableSection>
<MkFoldableSection>
<template #header>{{ i18n.ts._keyboardShortCut._category.postForm }}</template>
<div :class="$style.section">
<div :class="$style.title">{{ i18n.ts._keyboardShortCut._postForm.toggleVisibility }}</div>
<div v-if="!defaultStore.state.postFormVisibilityHotkey" :class="$style.caution">{{ i18n.ts._keyboardShortCut._postForm.featureWarn }}</div>
<div :class="$style.content">
<kbd>Ctrl</kbd>+<kbd>Shift</kbd>
</div>
</div>
<div :class="$style.section">
<div :class="$style.title">{{ i18n.ts._keyboardShortCut._postForm.toggleLocalOnly }}</div>
<div v-if="!defaultStore.state.postFormVisibilityHotkey" :class="$style.caution">{{ i18n.ts._keyboardShortCut._postForm.featureWarn }}</div>
<div :class="$style.content">
<kbd>Ctrl</kbd> + <kbd>Alt</kbd>
</div>
</div>
<div :class="$style.section">
<div :class="$style.title">{{ i18n.ts._keyboardShortCut._postForm.sendPost }}</div>
<div v-if="defaultStore.state.useEnterToSend" :class="$style.content">
<kbd>Enter</kbd>
</div>
<div v-else :class="$style.content">
<kbd>Ctrl</kbd> + <kbd>Enter</kbd>
</div>
</div>
</MkFoldableSection>
</div>
</MkSpacer>
</MkStickyContainer>
</template>

<script lang="ts" setup>
import { computed } from 'vue';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
import { defaultStore } from '@/store';

defineProps<{
popup?: boolean;
}>();

const headerActions = computed(() => []);

const headerTabs = computed(() => []);

definePageMetadata(() => ({
title: i18n.ts._keyboardShortCut.title,
icon: 'ti ti-keyboard',
}));

</script>

<style lang="scss" module>
.root {
background: var(--MI_THEME-bg);
}

.intro {
margin-bottom: 30px;
padding-bottom: 16px;
border-bottom: solid 1px var(--MI_THEME-divider);
}

.section {
&:not(:last-child) {
margin-bottom: 30px;
}
}

.title {
position: sticky;
z-index: 1;
top: var(--MI-stickyTop, 0px);
padding: 16px;
font-weight: bold;
-webkit-backdrop-filter: var(--MI-blur, blur(10px));
backdrop-filter: var(--MI-blur, blur(10px));
background-color: var(--MI_THEME-panel);
}

.content {
padding: 16px;
> kbd {
border-radius: 3px;
border:1px solid var(--MI_THEME-accent);
color: var(--MI_THEME-fg);
display: inline-block;
font-size: 0.85em;
font-weight: bold;
line-height: 1;
padding: 2px 4px;
white-space: nowrap;
}
}

.caution {
font-size: 0.8em;
padding: 16px;
background: var(--MI_THEME-infoWarnBg);
color: var(--MI_THEME-infoWarnFg);
border-radius: var(--MI-radius);
overflow: clip;
}

</style>
3 changes: 3 additions & 0 deletions packages/frontend/src/router/definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,9 @@ const routes: RouteDef[] = [{
}, {
path: '/mfc-cheat-sheet',
component: page(() => import('@/pages/mfc-cheat-sheet.vue')),
}, {
path: '/keyboard-shortcuts',
component: page(() => import('@/pages/keyboard-shortcut.vue')),
}, {
name: 'index',
path: '/',
Expand Down
1 change: 1 addition & 0 deletions packages/frontend/src/scripts/hotkey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const KEY_ALIASES = {
'left': 'ArrowLeft',
'right': 'ArrowRight',
'plus': ['+', ';'],
'/': ['/', '?'],
};

const MODIFIER_KEYS = ['ctrl', 'alt', 'shift'];
Expand Down

0 comments on commit e746616

Please sign in to comment.