diff options
| author | syuilo <syuilotan@yahoo.co.jp> | 2020-12-27 17:04:41 +0900 |
|---|---|---|
| committer | syuilo <syuilotan@yahoo.co.jp> | 2020-12-27 17:04:41 +0900 |
| commit | 3fc427b699b580f0dacbf7484174879a8df88f8a (patch) | |
| tree | 0f36adfd5e98b306d8379e7b39c33ec7f69e4bfa /src | |
| parent | Delete const.json (diff) | |
| download | sharkey-3fc427b699b580f0dacbf7484174879a8df88f8a.tar.gz sharkey-3fc427b699b580f0dacbf7484174879a8df88f8a.tar.bz2 sharkey-3fc427b699b580f0dacbf7484174879a8df88f8a.zip | |
nanka iroiro
Diffstat (limited to 'src')
| -rw-r--r-- | src/client/directives/hotkey.ts | 93 | ||||
| -rw-r--r-- | src/client/init.ts | 16 | ||||
| -rw-r--r-- | src/client/pages/settings/theme.vue | 2 | ||||
| -rw-r--r-- | src/client/scripts/hotkey.ts | 88 | ||||
| -rw-r--r-- | src/client/ui/_common_/common.vue | 2 | ||||
| -rw-r--r-- | src/client/ui/deck.vue | 11 | ||||
| -rw-r--r-- | src/client/ui/default.vue | 21 | ||||
| -rw-r--r-- | src/client/ui/desktop.vue | 15 | ||||
| -rw-r--r-- | src/client/ui/zen.vue | 20 |
9 files changed, 110 insertions, 158 deletions
diff --git a/src/client/directives/hotkey.ts b/src/client/directives/hotkey.ts index a1c49f0074..d813a95074 100644 --- a/src/client/directives/hotkey.ts +++ b/src/client/directives/hotkey.ts @@ -1,100 +1,11 @@ import { Directive } from 'vue'; -import keyCode from '../scripts/keycode'; -import { concat } from '../../prelude/array'; - -type pattern = { - which: string[]; - ctrl?: boolean; - shift?: boolean; - alt?: boolean; -}; - -type action = { - patterns: pattern[]; - - callback: Function; - - allowRepeat: boolean; -}; - -const getKeyMap = keymap => Object.entries(keymap).map(([patterns, callback]): action => { - const result = { - patterns: [], - callback: callback, - allowRepeat: true - } as action; - - if (patterns.match(/^\(.*\)$/) !== null) { - result.allowRepeat = false; - patterns = patterns.slice(1, -1); - } - - result.patterns = patterns.split('|').map(part => { - const pattern = { - which: [], - ctrl: false, - alt: false, - shift: false - } as pattern; - - const keys = part.trim().split('+').map(x => x.trim().toLowerCase()); - for (const key of keys) { - switch (key) { - case 'ctrl': pattern.ctrl = true; break; - case 'alt': pattern.alt = true; break; - case 'shift': pattern.shift = true; break; - default: pattern.which = keyCode(key).map(k => k.toLowerCase()); - } - } - - return pattern; - }); - - return result; -}); - -const ignoreElemens = ['input', 'textarea']; - -function match(e: KeyboardEvent, patterns: action['patterns']): boolean { - const key = e.code.toLowerCase(); - return patterns.some(pattern => pattern.which.includes(key) && - pattern.ctrl === e.ctrlKey && - pattern.shift === e.shiftKey && - pattern.alt === e.altKey && - !e.metaKey - ); -} +import { makeHotkey } from '../scripts/hotkey'; export default { mounted(el, binding) { el._hotkey_global = binding.modifiers.global === true; - const actions = getKeyMap(binding.value); - - // flatten - const reservedKeys = concat(actions.map(a => a.patterns)); - - el._misskey_reservedKeys = reservedKeys; - - el._keyHandler = (e: KeyboardEvent) => { - const targetReservedKeys = document.activeElement ? ((document.activeElement as any)._misskey_reservedKeys || []) : []; - if (document.activeElement && ignoreElemens.some(el => document.activeElement.matches(el))) return; - if (document.activeElement && document.activeElement.attributes['contenteditable']) return; - - for (const action of actions) { - const matched = match(e, action.patterns); - - if (matched) { - if (!action.allowRepeat && e.repeat) return; - if (el._hotkey_global && match(e, targetReservedKeys)) return; - - e.preventDefault(); - e.stopPropagation(); - action.callback(e); - break; - } - } - }; + el._keyHandler = makeHotkey(binding.value); if (el._hotkey_global) { document.addEventListener('keydown', el._keyHandler); diff --git a/src/client/init.ts b/src/client/init.ts index 4af6f25780..05fbec3a34 100644 --- a/src/client/init.ts +++ b/src/client/init.ts @@ -45,15 +45,17 @@ import { router } from '@/router'; import { applyTheme } from '@/scripts/theme'; import { isDeviceDarkmode } from '@/scripts/is-device-darkmode'; import { i18n } from '@/i18n'; -import { stream, isMobile, dialog } from '@/os'; +import { stream, isMobile, dialog, post } from '@/os'; import * as sound from '@/scripts/sound'; import { $i, refreshAccount, login, updateAccount, signout } from '@/account'; import { defaultStore, ColdDeviceStorage } from '@/store'; import { fetchInstance, instance } from '@/instance'; +import { makeHotkey } from './scripts/hotkey'; +import { search } from './scripts/search'; console.info(`Misskey v${version}`); -window.clearTimeout(window.mkBootTimer); +window.clearTimeout((window as any).mkBootTimer); if (_DEV_) { console.warn('Development mode!!!'); @@ -214,6 +216,16 @@ window.matchMedia('(prefers-color-scheme: dark)').addListener(mql => { }); //#endregion +// shortcut +document.addEventListener('keydown', makeHotkey({ + 'd': () => { + defaultStore.set('darkMode', !defaultStore.state.darkMode); + }, + 'p|n': post, + 's': search, + //TODO: 'h|/': help +})); + watch(defaultStore.reactiveState.useBlurEffectForModal, v => { document.documentElement.style.setProperty('--modalBgFilter', v ? 'blur(4px)' : 'none'); }, { immediate: true }); diff --git a/src/client/pages/settings/theme.vue b/src/client/pages/settings/theme.vue index 720874fd54..d83e243081 100644 --- a/src/client/pages/settings/theme.vue +++ b/src/client/pages/settings/theme.vue @@ -99,7 +99,7 @@ export default defineComponent({ const lightThemes = computed(() => themes.value.filter(t => t.base == 'light' || t.kind == 'light')); const darkTheme = computed(ColdDeviceStorage.makeGetterSetter('darkTheme')); const lightTheme = computed(ColdDeviceStorage.makeGetterSetter('lightTheme')); - const darkMode = computed(defaultStore.makeGetterSetter('darkMode')); + const darkMode = defaultStore.reactiveState.darkMode; const syncDeviceDarkMode = computed(ColdDeviceStorage.makeGetterSetter('syncDeviceDarkMode')); const wallpaper = ref(localStorage.getItem('wallpaper')); diff --git a/src/client/scripts/hotkey.ts b/src/client/scripts/hotkey.ts new file mode 100644 index 0000000000..2b3f491fd8 --- /dev/null +++ b/src/client/scripts/hotkey.ts @@ -0,0 +1,88 @@ +import keyCode from './keycode'; + +type Keymap = Record<string, Function>; + +type Pattern = { + which: string[]; + ctrl?: boolean; + shift?: boolean; + alt?: boolean; +}; + +type Action = { + patterns: Pattern[]; + callback: Function; + allowRepeat: boolean; +}; + +const parseKeymap = (keymap: Keymap) => Object.entries(keymap).map(([patterns, callback]): Action => { + const result = { + patterns: [], + callback: callback, + allowRepeat: true + } as Action; + + if (patterns.match(/^\(.*\)$/) !== null) { + result.allowRepeat = false; + patterns = patterns.slice(1, -1); + } + + result.patterns = patterns.split('|').map(part => { + const pattern = { + which: [], + ctrl: false, + alt: false, + shift: false + } as Pattern; + + const keys = part.trim().split('+').map(x => x.trim().toLowerCase()); + for (const key of keys) { + switch (key) { + case 'ctrl': pattern.ctrl = true; break; + case 'alt': pattern.alt = true; break; + case 'shift': pattern.shift = true; break; + default: pattern.which = keyCode(key).map(k => k.toLowerCase()); + } + } + + return pattern; + }); + + return result; +}); + +const ignoreElemens = ['input', 'textarea']; + +function match(e: KeyboardEvent, patterns: Action['patterns']): boolean { + const key = e.code.toLowerCase(); + return patterns.some(pattern => pattern.which.includes(key) && + pattern.ctrl === e.ctrlKey && + pattern.shift === e.shiftKey && + pattern.alt === e.altKey && + !e.metaKey + ); +} + +export const makeHotkey = (keymap: Keymap) => { + const actions = parseKeymap(keymap); + + return (e: KeyboardEvent) => { + if (document.activeElement) { + if (ignoreElemens.some(el => document.activeElement!.matches(el))) return; + if (document.activeElement.attributes['contenteditable']) return; + } + + for (const action of actions) { + const matched = match(e, action.patterns); + + if (matched) { + if (!action.allowRepeat && e.repeat) return; + + e.preventDefault(); + e.stopPropagation(); + action.callback(e); + break; + } + } + }; +}; diff --git a/src/client/ui/_common_/common.vue b/src/client/ui/_common_/common.vue index a4d1661f46..e5cdaca235 100644 --- a/src/client/ui/_common_/common.vue +++ b/src/client/ui/_common_/common.vue @@ -17,7 +17,7 @@ import { defineAsyncComponent, defineComponent } from 'vue'; import { stream, popup, popups, uploads, pendingApiRequestsCount } from '@/os'; import * as sound from '@/scripts/sound'; -import { $i, $i } from '@/account'; +import { $i } from '@/account'; export default defineComponent({ components: { diff --git a/src/client/ui/deck.vue b/src/client/ui/deck.vue index 0cbfd7a48b..6cdf56f3c3 100644 --- a/src/client/ui/deck.vue +++ b/src/client/ui/deck.vue @@ -1,5 +1,5 @@ <template> -<div class="mk-deck" :class="`${deckStore.reactiveState.columnAlign.value}`" v-hotkey.global="keymap" @contextmenu.self.prevent="onContextmenu" +<div class="mk-deck" :class="`${deckStore.reactiveState.columnAlign.value}`" @contextmenu.self.prevent="onContextmenu" :style="{ '--deckMargin': deckStore.reactiveState.columnMargin.value + 'px' }" > <XSidebar ref="nav"/> @@ -35,7 +35,6 @@ import { faPlus, faPencilAlt, faChevronLeft, faBars, faCircle } from '@fortaweso import { } from '@fortawesome/free-regular-svg-icons'; import { v4 as uuid } from 'uuid'; import { host } from '@/config'; -import { search } from '@/scripts/search'; import DeckColumnCore from '@/ui/deck/column-core.vue'; import XSidebar from '@/components/sidebar.vue'; import { getScrollContainer } from '@/scripts/scroll'; @@ -75,14 +74,6 @@ export default defineComponent({ } return false; }, - keymap(): any { - return { - 'p': this.post, - 'n': this.post, - 's': this.search, - 'h|/': this.help - }; - }, }, created() { diff --git a/src/client/ui/default.vue b/src/client/ui/default.vue index 066b9dd354..1a3c336f39 100644 --- a/src/client/ui/default.vue +++ b/src/client/ui/default.vue @@ -1,5 +1,5 @@ <template> -<div class="mk-app" v-hotkey.global="keymap" :class="{ wallpaper }"> +<div class="mk-app" :class="{ wallpaper }"> <XSidebar ref="nav" class="sidebar"/> <div class="contents" ref="contents"> @@ -57,7 +57,6 @@ import { defineComponent, defineAsyncComponent, markRaw } from 'vue'; import { faLayerGroup, faBars, faHome, faCircle, faWindowMaximize, faColumns, faPencilAlt } from '@fortawesome/free-solid-svg-icons'; import { faBell } from '@fortawesome/free-regular-svg-icons'; import { host } from '@/config'; -import { search } from '@/scripts/search'; import { StickySidebar } from '@/scripts/sticky-sidebar'; import XSidebar from '@/components/sidebar.vue'; import XCommon from './_common_/common.vue'; @@ -65,7 +64,6 @@ import XHeader from './_common_/header.vue'; import XSide from './default.side.vue'; import * as os from '@/os'; import { sidebarDef } from '@/sidebar'; -import { ColdDeviceStorage } from '@/store'; const DESKTOP_THRESHOLD = 1100; @@ -101,19 +99,6 @@ export default defineComponent({ }, computed: { - keymap(): any { - return { - 'd': () => { - if (ColdDeviceStorage.get('syncDeviceDarkMode')) return; - this.$store.set('darkMode', !this.$store.state.darkMode); - }, - 'p': os.post, - 'n': os.post, - 's': () => search(), - 'h|/': this.help - }; - }, - navIndicated(): boolean { for (const def in this.menuDef) { if (def === 'notifications') continue; // 通知は下にボタンとして表示されてるから @@ -199,10 +184,6 @@ export default defineComponent({ window.scroll({ top: 0, behavior: 'smooth' }); }, - help() { - this.$router.push('/docs/keyboard-shortcut'); - }, - onTransition() { if (window._scroll) window._scroll(); }, diff --git a/src/client/ui/desktop.vue b/src/client/ui/desktop.vue index 7c5824c4c0..199c0fdaaf 100644 --- a/src/client/ui/desktop.vue +++ b/src/client/ui/desktop.vue @@ -1,5 +1,5 @@ <template> -<div class="mk-app" v-hotkey.global="keymap" :class="{ wallpaper }" @contextmenu.prevent="() => {}"> +<div class="mk-app" :class="{ wallpaper }" @contextmenu.prevent="() => {}"> <XSidebar ref="nav" class="sidebar"/> <XCommon/> @@ -31,19 +31,6 @@ export default defineComponent({ }, computed: { - keymap(): any { - return { - 'd': () => { - if (ColdDeviceStorage.get('syncDeviceDarkMode')) return; - this.$store.set('darkMode', !this.$store.state.darkMode); - }, - 'p': os.post, - 'n': os.post, - 's': () => search(), - 'h|/': this.help - }; - }, - menu(): string[] { return this.$store.state.menu; }, diff --git a/src/client/ui/zen.vue b/src/client/ui/zen.vue index 1c1334bece..c2a307da73 100644 --- a/src/client/ui/zen.vue +++ b/src/client/ui/zen.vue @@ -1,5 +1,5 @@ <template> -<div class="mk-app" v-hotkey.global="keymap"> +<div class="mk-app"> <div class="contents"> <header class="header"> <XHeader :info="pageInfo"/> @@ -26,11 +26,8 @@ import { defineComponent, defineAsyncComponent } from 'vue'; import { faLayerGroup, faBars, faHome, faCircle } from '@fortawesome/free-solid-svg-icons'; import { faBell } from '@fortawesome/free-regular-svg-icons'; import { host } from '@/config'; -import { search } from '@/scripts/search'; import XHeader from './_common_/header.vue'; import XCommon from './_common_/common.vue'; -import * as os from '@/os'; -import { ColdDeviceStorage } from '@/store'; export default defineComponent({ components: { @@ -47,21 +44,6 @@ export default defineComponent({ }; }, - computed: { - keymap(): any { - return { - 'd': () => { - if (ColdDeviceStorage.get('syncDeviceDarkMode')) return; - this.$store.set('darkMode', !this.$store.state.darkMode); - }, - 'p': os.post, - 'n': os.post, - 's': search, - 'h|/': this.help - }; - }, - }, - watch: { $route(to, from) { this.pageKey++; |