Compare commits

...

15 Commits

Author SHA1 Message Date
syuilo
195f676500 8.55.0 2018-09-19 08:38:18 +09:00
syuilo
a9a2f4820b Add keyboard shortcut doc 2018-09-19 08:36:06 +09:00
MeiMei
8414db57f0 Specify AP Cache-Control (#2735) 2018-09-19 07:17:19 +09:00
syuilo
609d68933e Add new shortcut 2018-09-19 02:51:06 +09:00
syuilo
a23b8cebbc 8.54.0 2018-09-19 02:41:09 +09:00
greenkeeper[bot]
89f6b03cd6 fix(package): update web-push to version 3.3.3 (#2733) 2018-09-19 02:39:57 +09:00
greenkeeper[bot]
7bc9de03a6 fix(package): update webpack to version 4.19.1 (#2732) 2018-09-19 02:39:15 +09:00
syuilo
3c865d6054 Add new shortcut 2018-09-19 02:35:32 +09:00
syuilo
fd770b008e Add new shortcut 2018-09-19 02:32:44 +09:00
syuilo
b0d60ef2c2 Add new shortcut 2018-09-19 02:27:19 +09:00
syuilo
7b9cea06ef Fix 2018-09-19 02:26:06 +09:00
syuilo
30608d3e22 8.53.0 2018-09-18 16:45:55 +09:00
syuilo
8bf4e55338 Improve keyboard shortcuts 2018-09-18 16:45:20 +09:00
syuilo
6ead1de383 Improve readability 2018-09-18 15:02:26 +09:00
syuilo
3b628ec3c4 将来的にバグに繋がりかねない挙動を修正 2018-09-18 15:02:15 +09:00
16 changed files with 195 additions and 22 deletions

View File

@@ -1,8 +1,8 @@
{
"name": "misskey",
"author": "syuilo <i@syuilo.com>",
"version": "8.52.0",
"clientVersion": "1.0.9894",
"version": "8.55.0",
"clientVersion": "1.0.9909",
"codename": "nighthike",
"main": "./built/index.js",
"private": true,
@@ -217,9 +217,9 @@
"vuewordcloud": "18.7.11",
"vuex": "3.0.1",
"vuex-persistedstate": "2.5.4",
"web-push": "3.3.2",
"web-push": "3.3.3",
"webfinger.js": "2.6.6",
"webpack": "4.19.0",
"webpack": "4.19.1",
"webpack-cli": "3.1.0",
"websocket": "1.0.26",
"ws": "6.0.0",

View File

@@ -1,3 +1,24 @@
<template>
<router-view id="app"></router-view>
<router-view id="app" v-hotkey.global="keymap"></router-view>
</template>
<script lang="ts">
import Vue from 'vue';
import { url, lang } from './config';
export default Vue.extend({
computed: {
keymap(): any {
return {
'h|slash': this.help
};
}
},
methods: {
help() {
window.open(`${url}/docs/${lang}/keyboard-shortcut`, '_blank');
}
}
});
</script>

View File

@@ -22,7 +22,10 @@ const getKeyMap = keymap => Object.entries(keymap).map(([patterns, callback]): a
result.patterns = patterns.split('|').map(part => {
const pattern = {
which: []
which: [],
ctrl: false,
alt: false,
shift: false
} as pattern;
part.trim().split('+').forEach(key => {
@@ -66,10 +69,10 @@ export default {
if (el._hotkey_global && targetReservedKeys.includes(`'${key}'`)) break;
const matched = action.patterns.some(pattern => {
let matched = pattern.which.includes(key);
if (pattern.ctrl && !e.ctrlKey) matched = false;
if (pattern.shift && !e.shiftKey) matched = false;
if (pattern.alt && !e.altKey) matched = false;
const matched = pattern.which.includes(key) &&
pattern.ctrl == e.ctrlKey &&
pattern.shift == e.shiftKey &&
pattern.alt == e.altKey;
if (matched) {
e.preventDefault();

View File

@@ -2,9 +2,9 @@
<div class="onchrpzrvnoruiaenfcqvccjfuupzzwv">
<div class="backdrop" ref="backdrop" @click="close"></div>
<div class="popover" :class="{ hukidasi }" ref="popover">
<template v-for="item in items">
<template v-for="item, i in items">
<div v-if="item === null"></div>
<button v-if="item" @click="clicked(item.action)" v-html="item.icon ? item.icon + ' ' + item.text : item.text"></button>
<button v-if="item" @click="clicked(item.action)" v-html="item.icon ? item.icon + ' ' + item.text : item.text" :tabindex="i"></button>
</template>
</div>
</div>

View File

@@ -97,10 +97,10 @@ export default Vue.extend({
watch: {
focus(i) {
this.$refs.buttons.childNodes[i].focus();
this.$refs.buttons.children[i].focus();
if (this.showFocus) {
this.title = this.$refs.buttons.childNodes[i].title;
this.title = this.$refs.buttons.children[i].title;
}
}
},

View File

@@ -51,7 +51,7 @@
<button class="reactionButton" :class="{ reacted: p.myReaction != null }" @click="react()" ref="reactButton" title="%i18n:@add-reaction%">
%fa:plus%<p class="count" v-if="p.reactions_count > 0">{{ p.reactions_count }}</p>
</button>
<button @click="menu" ref="menuButton">
<button @click="menu()" ref="menuButton">
%fa:ellipsis-h%
</button>
<!-- <button title="%i18n:@detail">
@@ -114,11 +114,14 @@ export default Vue.extend({
keymap(): any {
return {
'r|left': () => this.reply(true),
'a|plus': () => this.react(true),
'ctrl+q|ctrl+right': this.renoteDirectly,
'e|a|plus': () => this.react(true),
'q|right': () => this.renote(true),
'ctrl+q|ctrl+right': this.renoteDirectly,
'up|k|shift+tab': this.focusBefore,
'down|j|tab': this.focusAfter,
'esc': this.blur,
'm|o': () => this.menu(true),
's': this.toggleShowContent,
'1': () => this.reactDirectly('like'),
'2': () => this.reactDirectly('love'),
'3': () => this.reactDirectly('laugh'),
@@ -278,13 +281,18 @@ export default Vue.extend({
});
},
menu() {
menu(viaKeyboard = false) {
(this as any).os.new(MkNoteMenu, {
source: this.$refs.menuButton,
note: this.p
note: this.p,
animation: !viaKeyboard
}).$once('closed', this.focus);
},
toggleShowContent() {
this.showContent = !this.showContent;
},
focus() {
this.$el.focus();
},

View File

@@ -28,7 +28,7 @@ export default Vue.extend({
props: {
reply: {
type: Object,
required: true
required: false
},
animation: {

View File

@@ -1,5 +1,5 @@
<template>
<div class="account">
<div class="account" v-hotkey.global="keymap">
<button class="header" :data-active="isOpen" @click="toggle">
<span class="username">{{ $store.state.i.username }}<template v-if="!isOpen">%fa:angle-down%</template><template v-if="isOpen">%fa:angle-up%</template></span>
<mk-avatar class="avatar" :user="$store.state.i"/>
@@ -63,6 +63,13 @@ export default Vue.extend({
isOpen: false
};
},
computed: {
keymap(): any {
return {
'a|m': this.toggle
};
}
},
beforeDestroy() {
this.close();
},

View File

@@ -1,5 +1,5 @@
<template>
<div class="notifications">
<div class="notifications" v-hotkey.global="keymap">
<button :data-active="isOpen" @click="toggle" title="%i18n:@title%">
%fa:R bell%<template v-if="hasUnreadNotification">%fa:circle%</template>
</button>
@@ -19,11 +19,19 @@ export default Vue.extend({
isOpen: false
};
},
computed: {
hasUnreadNotification(): boolean {
return this.$store.getters.isSignedIn && this.$store.state.i.hasUnreadNotification;
},
keymap(): any {
return {
'shift+n': this.toggle
};
}
},
methods: {
toggle() {
this.isOpen ? this.close() : this.open();

View File

@@ -0,0 +1,96 @@
# Misskeyキーボードショートカットまとめ
## グローバル
これらのショートカットは基本的にどこでも使えます。
<table>
<thead>
<tr><th>ショートカット</th><th>効果</th><th>由来</th></tr>
</thead>
<tbody>
<tr><td><kbd class="key">P</kbd>, <kbd class="key">N</kbd></td><td>新規投稿</td><td><b>P</b>ost, <b>N</b>ew, <b>N</b>ote</td></tr>
<tr><td><kbd class="key">T</kbd></td><td>タイムラインの最も新しい投稿にフォーカス</td><td><b>T</b>imeline, <b>T</b>op</td></tr>
<tr><td><kbd class="group"><kbd class="key">Shift</kbd> + <kbd class="key">N</kbd></kbd></td><td>通知を表示/隠す</td><td><b>N</b>otifications</td></tr>
<tr><td><kbd class="key">A</kbd>, <kbd class="key">M</kbd></td><td>アカウントメニューを表示/隠す</td><td><b>A</b>ccount, <b>M</b>y, <b>M</b>e, <b>M</b>enu</td></tr>
<tr><td><kbd class="key">Z</kbd></td><td>上部のバーを隠す</td><td><b>Z</b>en</td></tr>
<tr><td><kbd class="key">H</kbd>, <kbd class="key">?</kbd></td><td>ヘルプを表示</td><td><b>H</b>elp</td></tr>
</tbody>
</table>
## 投稿にフォーカスされた状態
<table>
<thead>
<tr><th>ショートカット</th><th>効果</th><th>由来</th></tr>
</thead>
<tbody>
<tr><td><kbd class="key"></kbd>, <kbd class="key">K</kbd>, <kbd class="group"><kbd class="key">Shift</kbd> + <kbd class="key">Tab</kbd></kbd></td><td>上の投稿にフォーカスを移動</td><td>-</td></tr>
<tr><td><kbd class="key"></kbd>, <kbd class="key">J</kbd>, <kbd class="key">Tab</kbd></td><td>下の投稿にフォーカスを移動</td><td>-</td></tr>
<tr><td><kbd class="key"></kbd>, <kbd class="key">R</kbd></td><td>返信フォームを開く</td><td><b>R</b>eply</td></tr>
<tr><td><kbd class="key"></kbd>, <kbd class="key">Q</kbd></td><td>Renoteフォームを開く</td><td><b>Q</b>uote</td></tr>
<tr><td><kbd class="group"><kbd class="key">Ctrl</kbd> + <kbd class="key"></kbd></kbd>, <kbd class="group"><kbd class="key">Ctrl</kbd> + <kbd class="key">Q</kbd></kbd></td><td>即刻Renoteする(フォームを開かずに)</td><td>-</td></tr>
<tr><td><kbd class="key">E</kbd>, <kbd class="key">A</kbd>, <kbd class="key">+</kbd></td><td>リアクションフォームを開く</td><td><b>E</b>mote, re<b>A</b>ction</td></tr>
<tr><td><kbd class="key">0</kbd>~<kbd class="key">9</kbd></td><td>数字に対応したリアクションをする(対応については後述)</td><td>-</td></tr>
<tr><td><kbd class="key">M</kbd>, <kbd class="key">O</kbd></td><td>投稿に対するメニューを開く</td><td><b>M</b>ore, <b>O</b>ther</td></tr>
<tr><td><kbd class="key">S</kbd></td><td>CWで隠された部分を表示 or 隠す</td><td><b>S</b>how, <b>S</b>ee</td></tr>
<tr><td><kbd class="key">Esc</kbd></td><td>フォーカスを外す</td><td>-</td></tr>
</tbody>
</table>
## Renoteフォーム
<table>
<thead>
<tr><th>ショートカット</th><th>効果</th><th>由来</th></tr>
</thead>
<tbody>
<tr><td><kbd class="key">Enter</kbd></td><td>Renoteする</td><td>-</td></tr>
<tr><td><kbd class="key">Q</kbd></td><td>フォームを展開する</td><td><b>Q</b>uote</td></tr>
<tr><td><kbd class="key">Esc</kbd></td><td>フォームを閉じる</td><td>-</td></tr>
</tbody>
</table>
## リアクションフォーム
デフォルトで「👍」にフォーカスが当たっている状態です。
<table>
<thead>
<tr><th>ショートカット</th><th>効果</th><th>由来</th></tr>
</thead>
<tbody>
<tr><td><kbd class="key"></kbd>, <kbd class="key">K</kbd></td><td>上のリアクションにフォーカスを移動</td><td>-</td></tr>
<tr><td><kbd class="key"></kbd>, <kbd class="key">J</kbd></td><td>下のリアクションにフォーカスを移動</td><td>-</td></tr>
<tr><td><kbd class="key"></kbd>, <kbd class="key">H</kbd>, <kbd class="group"><kbd class="key">Shift</kbd> + <kbd class="key">Tab</kbd></kbd></td><td>左のリアクションにフォーカスを移動</td><td>-</td></tr>
<tr><td><kbd class="key"></kbd>, <kbd class="key">L</kbd>, <kbd class="key">Tab</kbd></td><td>右のリアクションにフォーカスを移動</td><td>-</td></tr>
<tr><td><kbd class="key">Enter</kbd>, <kbd class="key">Space</kbd>, <kbd class="key">+</kbd></td><td>リアクション確定</td><td>-</td></tr>
<tr><td><kbd class="key">0</kbd>~<kbd class="key">9</kbd></td><td>数字に対応したリアクションで確定(対応については後述)</td><td>-</td></tr>
<tr><td><kbd class="key">Esc</kbd></td><td>リアクションするのをやめる</td><td>-</td></tr>
</tbody>
</table>
## リアクションと数字キーの対応
<table>
<thead>
<tr><th>数字キー</th><th>リアクション</th></tr>
</thead>
<tbody>
<tr><td><kbd class="key">1</kbd></td><td>👍</td></tr>
<tr><td><kbd class="key">2</kbd></td><td>❤️</td></tr>
<tr><td><kbd class="key">3</kbd></td><td>😆</td></tr>
<tr><td><kbd class="key">4</kbd></td><td>🤔</td></tr>
<tr><td><kbd class="key">5</kbd></td><td>😮</td></tr>
<tr><td><kbd class="key">6</kbd></td><td>🎉</td></tr>
<tr><td><kbd class="key">7</kbd></td><td>💢</td></tr>
<tr><td><kbd class="key">8</kbd></td><td>😥</td></tr>
<tr><td><kbd class="key">9</kbd></td><td>😇</td></tr>
<tr><td><kbd class="key">0</kbd></td><td>🍮 or 🍣</td></tr>
</tbody>
</table>
# 例
<table>
<thead>
<tr><th>ショートカット</th><th>動作</th></tr>
</thead>
<tbody>
<tr><td><kbd class="key">t</kbd><kbd class="key">+</kbd><kbd class="key">+</kbd></td><td>タイムラインの最新の投稿に👍する</td></tr>
<tr><td><kbd class="key">t</kbd><kbd class="key">1</kbd></td><td>タイムラインの最新の投稿に👍する</td></tr>
<tr><td><kbd class="key">t</kbd><kbd class="key">0</kbd></td><td>タイムラインの最新の投稿に🍮する</td></tr>
</tbody>
</table>

View File

@@ -128,3 +128,24 @@ pre
> code
display block
padding 16px
kbd.group
display inline-block
padding 4px
background #fbfbfb
border 1px solid #d6d6d6
border-radius 4px
box-shadow 0 1px 1px rgba(0, 0, 0, 0.1)
kbd.key
display inline-block
padding 6px 8px
background #fff
border solid 1px #cecece
border-radius 4px
box-shadow 0 1px 1px rgba(0, 0, 0, 0.1)
td
> kbd.group,
> kbd.key
margin 4px

View File

@@ -75,6 +75,7 @@ router.get('/notes/:note', async (ctx, next) => {
}
ctx.body = pack(await renderNote(note, false));
ctx.set('Cache-Control', 'public, max-age=180');
setResponseType(ctx);
});
@@ -91,6 +92,7 @@ router.get('/notes/:note/activity', async ctx => {
}
ctx.body = pack(await packActivity(note));
ctx.set('Cache-Control', 'public, max-age=180');
setResponseType(ctx);
});
@@ -122,6 +124,7 @@ router.get('/users/:user/publickey', async ctx => {
if (isLocalUser(user)) {
ctx.body = pack(renderKey(user));
ctx.set('Cache-Control', 'public, max-age=180');
setResponseType(ctx);
} else {
ctx.status = 400;
@@ -136,6 +139,7 @@ async function userInfo(ctx: Router.IRouterContext, user: IUser) {
}
ctx.body = pack(await renderPerson(user as ILocalUser));
ctx.set('Cache-Control', 'public, max-age=180');
setResponseType(ctx);
}

View File

@@ -34,5 +34,6 @@ export default async (ctx: Router.IRouterContext) => {
);
ctx.body = pack(rendered);
ctx.set('Cache-Control', 'private, max-age=0, must-revalidate');
setResponseType(ctx);
};

View File

@@ -78,6 +78,7 @@ export default async (ctx: Router.IRouterContext) => {
// index page
const rendered = renderOrderedCollection(partOf, user.followersCount, `${partOf}?page=true`, null);
ctx.body = pack(rendered);
ctx.set('Cache-Control', 'private, max-age=0, must-revalidate');
setResponseType(ctx);
}
};

View File

@@ -78,6 +78,7 @@ export default async (ctx: Router.IRouterContext) => {
// index page
const rendered = renderOrderedCollection(partOf, user.followingCount, `${partOf}?page=true`, null);
ctx.body = pack(rendered);
ctx.set('Cache-Control', 'private, max-age=0, must-revalidate');
setResponseType(ctx);
}
};

View File

@@ -88,6 +88,7 @@ export default async (ctx: Router.IRouterContext) => {
);
ctx.body = pack(rendered);
ctx.set('Cache-Control', 'private, max-age=0, must-revalidate');
setResponseType(ctx);
} else {
// index page
@@ -96,6 +97,7 @@ export default async (ctx: Router.IRouterContext) => {
`${partOf}?page=true&since_id=000000000000000000000000`
);
ctx.body = pack(rendered);
ctx.set('Cache-Control', 'private, max-age=0, must-revalidate');
setResponseType(ctx);
}
};