Compare commits

..

37 Commits

Author SHA1 Message Date
syuilo
b427842679 12.65.5 2020-12-31 03:04:24 +09:00
syuilo
4ae172be57 Add blur MFM syntax 2020-12-31 03:02:09 +09:00
syuilo
e6705b1a65 Add MFM syntax 2020-12-31 02:51:51 +09:00
syuilo
bc22cabdb5 🎨 2020-12-31 02:43:24 +09:00
syuilo
7128b9f16a 🎨 2020-12-31 00:22:20 +09:00
syuilo
8c0490fef1 インスタンス情報に統計追加したり 2020-12-31 00:11:06 +09:00
syuilo
882a81636d 🎨 2020-12-30 19:26:47 +09:00
syuilo
24b9be76ba 🎨 2020-12-30 19:24:01 +09:00
syuilo
e763c6e661 プロモーション増殖バグ修正 2020-12-30 17:31:59 +09:00
syuilo
899e2c73d7 12.65.4 2020-12-30 13:14:02 +09:00
syuilo
10cb15b000 nanka iroiro 2020-12-30 13:07:16 +09:00
syuilo
873d4bd707 clean up 2020-12-30 11:08:41 +09:00
syuilo
97dea72c94 サイトのタイトルが変わらない問題を修正 2020-12-30 11:01:33 +09:00
syuilo
7d49f260b8 12.65.3 2020-12-30 10:17:51 +09:00
syuilo
3055e6d8c7 localeとthemeのキャッシュクリア実装 2020-12-30 10:15:16 +09:00
syuilo
2c93246860 Tweak note collapse threshold 2020-12-30 10:03:57 +09:00
syuilo
360c820b9d Resolve #3620 2020-12-30 09:58:57 +09:00
syuilo
87847c6ed5 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2020-12-30 09:27:23 +09:00
syuilo
4874f54d4d 🎨 2020-12-30 09:27:19 +09:00
dependabot-preview[bot]
ff73efcc08 Merge pull request #7040 from syuilo/dependabot/npm_and_yarn/vue-color-2.8.1 2020-12-29 20:30:32 +00:00
dependabot-preview[bot]
4ee64cbd9e Merge pull request #7039 from syuilo/dependabot/npm_and_yarn/typescript-4.1.3 2020-12-29 20:30:29 +00:00
dependabot-preview[bot]
0c40a86fca Bump vue-color from 2.7.1 to 2.8.1
Bumps [vue-color](https://github.com/xiaokaike/vue-color) from 2.7.1 to 2.8.1.
- [Release notes](https://github.com/xiaokaike/vue-color/releases)
- [Commits](https://github.com/xiaokaike/vue-color/compare/v2.7.1...v2.8.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-12-29 20:22:07 +00:00
dependabot-preview[bot]
f92eed0549 Bump typescript from 4.1.2 to 4.1.3
Bumps [typescript](https://github.com/Microsoft/TypeScript) from 4.1.2 to 4.1.3.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](https://github.com/Microsoft/TypeScript/compare/v4.1.2...v4.1.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-12-29 20:22:00 +00:00
dependabot-preview[bot]
69ed8cc409 Merge pull request #7038 from syuilo/dependabot/npm_and_yarn/re2-1.15.9 2020-12-29 20:21:08 +00:00
dependabot-preview[bot]
4fff1279db Bump re2 from 1.15.8 to 1.15.9
Bumps [re2](https://github.com/uhop/node-re2) from 1.15.8 to 1.15.9.
- [Release notes](https://github.com/uhop/node-re2/releases)
- [Commits](https://github.com/uhop/node-re2/compare/1.15.8...1.15.9)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-12-29 20:13:45 +00:00
syuilo
d80699e454 12.65.2 2020-12-29 22:01:49 +09:00
syuilo
deee1dbf53 New Crowdin updates (#7031)
* New translations ja-JP.yml (Chinese Traditional)

* New translations ja-JP.yml (Chinese Traditional)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Chinese Simplified)

* New translations deck.md (Chinese Simplified)

* New translations deck.md (Chinese Simplified)

* New translations deck.md (Chinese Simplified)

* New translations mfm.md (Chinese Simplified)

* New translations ja-JP.yml (Italian)

* New translations aiscript.md (Haitian Creole)

* New translations deck.md (Haitian Creole)

* New translations timelines.md (Haitian Creole)

* New translations theme.md (Haitian Creole)

* New translations stream.md (Haitian Creole)

* New translations reversi-bot.md (Haitian Creole)

* New translations reaction.md (Haitian Creole)

* New translations pages.md (Haitian Creole)

* New translations mute.md (Haitian Creole)

* New translations keyboard-shortcut.md (Haitian Creole)

* New translations follow.md (Haitian Creole)

* New translations custom-emoji.md (Haitian Creole)

* New translations create-plugin.md (Haitian Creole)

* New translations api.md (Haitian Creole)

* New translations ja-JP.yml (Haitian Creole)

* New translations aiscript.md (Italian)

* New translations mfm.md (Italian)

* New translations deck.md (Italian)

* New translations timelines.md (Italian)

* New translations theme.md (Italian)

* New translations stream.md (Italian)

* New translations reversi-bot.md (Italian)

* New translations reaction.md (Italian)

* New translations pages.md (Italian)

* New translations mute.md (Italian)

* New translations keyboard-shortcut.md (Italian)

* New translations follow.md (Italian)

* New translations custom-emoji.md (Italian)

* New translations create-plugin.md (Italian)

* New translations api.md (Italian)

* New translations mfm.md (Haitian Creole)
2020-12-29 22:00:52 +09:00
syuilo
067588845b UI tweaks 2020-12-29 22:00:02 +09:00
syuilo
b177b0cafc タイムラインの上に設置した投稿フォームでコンテキストメニューが表示できない問題を修正 2020-12-29 21:18:35 +09:00
syuilo
5679777010 Improve usability 2020-12-29 21:08:16 +09:00
syuilo
a70c24cd1e テキストを選択した状態でノートのコンテキストメニューが開けない問題を修正 2020-12-29 21:08:08 +09:00
syuilo
357f3dd258 12.65.1 2020-12-29 17:45:57 +09:00
syuilo
d815838762 カラムのフレキシブル設定を上下分割されていても適用するように 2020-12-29 17:40:53 +09:00
syuilo
4ceef78599 モバイルの下のやつ改修 2020-12-29 17:31:46 +09:00
syuilo
d5811633ea タイムラインの上のバーを調整 2020-12-29 17:11:12 +09:00
syuilo
32265da72c LTL/GTLの有効状態を反映 2020-12-29 16:58:14 +09:00
syuilo
ef94236e7f Fix doc link 2020-12-29 16:45:35 +09:00
78 changed files with 3042 additions and 312 deletions

View File

@@ -669,7 +669,8 @@ left: "Links"
center: "Mitte"
wide: "Breit"
narrow: "Schmal"
reloadToApplySetting: "Einstellungen treten nach einer Aktualisierung der Seite in Kraft. Jetzt aktualisieren?"
reloadToApplySetting: "Diese Einstellung tritt nach einer Aktualisierung der Seite in Kraft. Jetzt aktualisieren?"
showTitlebar: "Titelleiste anzeigen"
_aboutMisskey:
about: "Misskey ist Open-Source-Software die von syuilo seit 2014 entwickelt wird."
contributors: "Hauptmitwirkende"

View File

@@ -669,7 +669,8 @@ left: "Left"
center: "Center"
wide: "Wide"
narrow: "Narrow"
reloadToApplySetting: "Settings will be applied upon page reload. Reload now?"
reloadToApplySetting: "This setting will be applied upon page reload. Reload now?"
showTitlebar: "Show title bar"
_aboutMisskey:
about: "Misskey is open-source software being developed by syuilo since 2014."
contributors: "Main contributors"

1
locales/ht-HT.yml Normal file
View File

@@ -0,0 +1 @@
---

1
locales/it-IT.yml Normal file
View File

@@ -0,0 +1 @@
---

View File

@@ -1,5 +1,6 @@
_lang_: "日本語"
headlineMisskey: "ノートでつながるネットワーク"
introMisskey: "ようこそMisskeyは、オープンソースの分散型マイクロブログサービスです。\n「ート」を作成して、いま起こっていることを共有したり、あなたについて皆に発信しよう📡\n「リアクション」機能で、皆のートに素早く反応を追加することもできます👍\n新しい世界を探検しよう🚀"
monthAndDay: "{month}月 {day}日"
search: "検索"
@@ -49,6 +50,7 @@ copyUsername: "ユーザー名をコピー"
searchUser: "ユーザーを検索"
reply: "返信"
loadMore: "もっと見る"
showMore: "もっと見る"
youGotNewFollower: "フォローされました"
receiveFollowRequest: "フォローリクエストされました"
followRequestAccepted: "フォローが承認されました"
@@ -671,6 +673,10 @@ wide: "広い"
narrow: "狭い"
reloadToApplySetting: "設定はページリロード後に反映されます。今すぐリロードしますか?"
showTitlebar: "タイトルバーを表示する"
clearCache: "キャッシュをクリア"
onlineUsersCount: "{n}人がオンライン"
nUsers: "{n}ユーザー"
nNotes: "{n}ノート"
_aboutMisskey:
about: "Misskeyはsyuiloによって2014年から開発されている、オープンソースのソフトウェアです。"
@@ -730,11 +736,19 @@ _mfm:
bounce: "アニメーション(バウンド)"
bounceDescription: "ぽよんぽよん弾むようなアニメーションを与えます。"
shake: "アニメーション(ぶるぶる)"
shakeDescription: "ぶるぶるるアニメーションを与えます。"
shakeDescription: "ぶるぶる震えるアニメーションを与えます。"
twitch: "アニメーション(ブレ)"
twitchDescription: "激しくブレるアニメーションを与えます。"
spin: "アニメーション(回転)"
spinDescription: "回転するアニメーションを与えます。"
x2: "大きく"
x2Description: "内容を大きく表示します。"
x3: "とても大きく"
x3Description: "内容をとても大きく表示します。"
x4: "究極に大きく"
x4Description: "内容を究極に大きく表示します。"
blur: "ぼかし"
blurDescription: "内容をぼかすことができます。ポインターを上に乗せるとはっきり見えるようになります。"
_reversi:
reversi: "リバーシ"
@@ -1013,6 +1027,7 @@ _widgets:
postForm: "投稿フォーム"
slideshow: "スライドショー"
button: "ボタン"
onlineUsers: "オンラインユーザー"
_cw:
hide: "隠す"

View File

@@ -670,6 +670,7 @@ center: "中央"
wide: "宽"
narrow: "窄"
reloadToApplySetting: "页面刷新后设置才会生效。是否现在刷新页面?"
showTitlebar: "显示标题栏"
_aboutMisskey:
about: "Misskey是由syuilo于2014年开发的开源软件。"
contributors: "主要贡献者"

View File

@@ -618,10 +618,13 @@ clips: "標籤"
experimentalFeatures: "測試中的功能"
developer: "開發者"
showGapBetweenNotesInTimeline: "分開顯示時間線上的箋文。"
duplicate: "複製"
left: "左"
center: "向中央"
wide: "寬"
narrow: "窄"
reloadToApplySetting: "設定將會在頁面重新載入之後生效。要現在就重載頁面嗎?"
showTitlebar: "顯示標題列"
_aboutMisskey:
about: "Misskey是由syuilo於2014年開發的開源軟件。"
contributors: "主要貢獻者"
@@ -636,6 +639,7 @@ _nsfw:
ignore: "不隱藏NSFW內容"
force: "隱藏所有內容"
_mfm:
cheatSheet: "MFM代碼小抄"
mention: "提及"
hashtag: "#tag"
url: "URL"

View File

@@ -1,7 +1,7 @@
{
"name": "misskey",
"author": "syuilo <syuilotan@yahoo.co.jp>",
"version": "12.65.0",
"version": "12.65.5",
"codename": "indigo",
"repository": {
"type": "git",
@@ -204,7 +204,7 @@
"qrcode": "1.4.4",
"random-seed": "0.3.0",
"ratelimiter": "3.4.1",
"re2": "1.15.8",
"re2": "1.15.9",
"recaptcha-promise": "1.0.0",
"reconnecting-websocket": "4.4.0",
"redis": "3.0.2",
@@ -237,14 +237,14 @@
"tslint": "6.1.3",
"tslint-sonarts": "1.9.0",
"typeorm": "0.2.29",
"typescript": "4.1.2",
"typescript": "4.1.3",
"ulid": "2.3.0",
"url-loader": "4.1.1",
"uuid": "8.3.2",
"v-debounce": "0.1.2",
"vanilla-tilt": "1.7.0",
"vue": "3.0.3",
"vue-color": "2.7.1",
"vue-color": "2.8.1",
"vue-json-pretty": "1.7.1",
"vue-loader": "16.0.0",
"vue-prism-editor": "2.0.0-alpha.2",

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@@ -49,7 +49,7 @@ export default defineComponent({
const el = this.$slots.default({
item: item
})[0];
el.key = item.id;
if (el.key == null && item.id) el.key = item.id;
if (
i != this.items.length - 1 &&

View File

@@ -0,0 +1,34 @@
<template>
<div class="xfbouadm" v-if="meta" :style="{ backgroundImage: `url(${ meta.backgroundImageUrl })` }">
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import * as os from '@/os';
export default defineComponent({
components: {
},
data() {
return {
meta: null,
};
},
created() {
os.api('meta', { detail: true }).then(meta => {
this.meta = meta;
});
},
});
</script>
<style lang="scss" scoped>
.xfbouadm {
background-position: center;
background-size: cover;
}
</style>

View File

@@ -11,6 +11,11 @@ export default defineComponent({
required: false,
default: 'span',
},
textTag: {
type: String,
required: false,
default: null,
},
},
render() {
let str = this.src;
@@ -32,6 +37,6 @@ export default defineComponent({
str = str.substr(nextBracketClose + 1);
}
return h(this.tag, parsed.map(x => typeof x === 'string' ? x : this.$slots[x.arg]()));
return h(this.tag, parsed.map(x => typeof x === 'string' ? (this.textTag ? h(this.textTag, x) : x) : this.$slots[x.arg]()));
}
});

View File

@@ -14,6 +14,15 @@ export default defineComponent({
</script>
<style lang="scss">
._mfm_blur_ {
filter: blur(6px);
transition: filter 0.3s;
&:hover {
filter: blur(0px);
}
}
@keyframes mfm-spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }

View File

@@ -129,6 +129,23 @@ export default defineComponent({
style = `transform: ${transform};`;
break;
}
case 'x2': {
style = `font-size: 200%;`;
break;
}
case 'x3': {
style = `font-size: 400%;`;
break;
}
case 'x4': {
style = `font-size: 600%;`;
break;
}
case 'blur': {
return h('span', {
class: '_mfm_blur_',
}, genEl(token.children));
}
}
if (style == null) {
return h('span', {}, ['[', token.node.props.name, ...genEl(token.children), ']']);

View File

@@ -36,7 +36,7 @@
<span class="localOnly" v-if="note.localOnly"><Fa :icon="faBiohazard"/></span>
</div>
</div>
<article class="article" @contextmenu.prevent.stop="onContextmenu">
<article class="article" @contextmenu.stop="onContextmenu">
<MkAvatar class="avatar" :user="appearNote.user"/>
<div class="main">
<XNoteHeader class="header" :note="appearNote" :mini="true"/>
@@ -46,7 +46,7 @@
<Mfm v-if="appearNote.cw != ''" class="text" :text="appearNote.cw" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/>
<XCwButton v-model:value="showContent" :note="appearNote"/>
</p>
<div class="content" v-show="appearNote.cw == null || showContent">
<div class="content" :class="{ collapsed }" v-show="appearNote.cw == null || showContent">
<div class="text">
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ $ts.private }})</span>
<MkA class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><Fa :icon="faReply"/></MkA>
@@ -59,6 +59,9 @@
<XPoll v-if="appearNote.poll" :note="appearNote" ref="pollViewer" class="poll"/>
<MkUrlPreview v-for="url in urls" :url="url" :key="url" :compact="true" :detail="detail" class="url-preview"/>
<div class="renote" v-if="appearNote.renote"><XNotePreview :note="appearNote.renote"/></div>
<button v-if="collapsed" class="fade _button" @click="collapsed = false">
<span>{{ $ts.showMore }}</span>
</button>
</div>
<MkA v-if="appearNote.channel && !inChannel" class="channel" :to="`/channels/${appearNote.channel.id}`"><Fa :icon="faSatelliteDish"/> {{ appearNote.channel.name }}</MkA>
</div>
@@ -174,6 +177,7 @@ export default defineComponent({
conversation: [],
replies: [],
showContent: false,
collapsed: false,
isDeleted: false,
muted: false,
faEdit, faBolt, faTimes, faBullhorn, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faBiohazard, faPlug, faSatelliteDish
@@ -273,6 +277,12 @@ export default defineComponent({
this.connection = os.stream;
}
this.collapsed = this.appearNote.text && (
(this.appearNote.text.split('\n').length > 9) ||
(this.appearNote.text.length > 500)
);
this.muted = await checkWordMute(this.appearNote, this.$i, this.$store.state.mutedWords);
// plugin
if (noteViewInterruptors.length > 0) {
let result = this.note;
@@ -282,8 +292,6 @@ export default defineComponent({
this.$emit('update:note', Object.freeze(result));
}
this.muted = await checkWordMute(this.appearNote, this.$i, this.$store.state.mutedWords);
if (this.detail) {
os.api('notes/children', {
noteId: this.appearNote.id,
@@ -1038,6 +1046,37 @@ export default defineComponent({
}
> .content {
&.collapsed {
position: relative;
max-height: 9em;
overflow: hidden;
> .fade {
display: block;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 64px;
background: linear-gradient(0deg, var(--panel), var(--X15));
> span {
display: inline-block;
background: var(--panel);
padding: 6px 10px;
font-size: 0.8em;
border-radius: 999px;
box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
}
&:hover {
> span {
background: var(--panelHighlight);
}
}
}
}
> .text {
overflow-wrap: break-word;

View File

@@ -1,6 +1,6 @@
<template>
<XWindow ref="window"
:initial-width="700"
:initial-width="500"
:initial-height="500"
:can-resize="true"
:close-right="true"

View File

@@ -357,12 +357,6 @@ export default defineComponent({
top: 0;
left: 0;
z-index: 1001;
> div {
> .notifications {
display: none;
}
}
}
&:not(.hidden) {

View File

@@ -123,7 +123,7 @@ export default defineComponent({
box-shadow: none;
text-decoration: none;
background: var(--buttonBg);
border-radius: 8px;
border-radius: 999px;
overflow: hidden;
&:not(:disabled):hover {

View File

@@ -91,10 +91,6 @@ if (_DEV_) {
// タッチデバイスでCSSの:hoverを機能させる
document.addEventListener('touchend', () => {}, { passive: true });
if (localStorage.theme == null) {
applyTheme(require('@/themes/l-light.json5'));
}
//#region SEE: https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
// TODO: いつの日にか消したい
const vh = window.innerHeight * 0.01;
@@ -204,7 +200,7 @@ watch(defaultStore.reactiveState.darkMode, (darkMode) => {
const themes = builtinThemes.concat(ColdDeviceStorage.get('themes'));
applyTheme(themes.find(x => x.id === (darkMode ? ColdDeviceStorage.get('darkTheme') : ColdDeviceStorage.get('lightTheme'))));
});
});
}, { immediate: localStorage.theme == null });
//#region Sync dark mode
if (ColdDeviceStorage.get('syncDeviceDarkMode')) {

View File

@@ -23,6 +23,18 @@
</FormGroup>
<FormLink v-if="meta.tosUrl" :to="meta.tosUrl" external>{{ $ts.tos }}</FormLink>
<FormGroup v-if="stats">
<template #label>{{ $ts.statistics }}</template>
<FormKeyValueView>
<template #key>{{ $ts.users }}</template>
<template #value>{{ number(stats.originalUsersCount) }}</template>
</FormKeyValueView>
<FormKeyValueView>
<template #key>{{ $ts.notes }}</template>
<template #value>{{ number(stats.originalNotesCount) }}</template>
</FormKeyValueView>
</FormGroup>
</FormBase>
</template>
@@ -35,6 +47,7 @@ import FormBase from '@/components/form/base.vue';
import FormGroup from '@/components/form/group.vue';
import FormKeyValueView from '@/components/form/key-value-view.vue';
import * as os from '@/os';
import number from '@/filters/number';
export default defineComponent({
components: {
@@ -52,7 +65,7 @@ export default defineComponent({
},
version,
instanceName,
serverInfo: null,
stats: null,
faInfoCircle
}
},
@@ -62,6 +75,16 @@ export default defineComponent({
return this.$instance;
},
},
created() {
os.api('stats').then(stats => {
this.stats = stats;
});
},
methods: {
number
}
});
</script>

View File

@@ -22,7 +22,7 @@
<XPostForm :channel="channel" class="post-form _content _panel _vMargin" fixed v-if="$i"/>
<XTimeline class="_content _vMargin" src="channel" :channel="channelId" @before="before" @after="after"/>
<XTimeline class="_content _vMargin _noGap_" src="channel" :channel="channelId" @before="before" @after="after"/>
</div>
</template>

View File

@@ -3,7 +3,7 @@
<div class="title">{{ title }}</div>
<div class="body" v-html="body"></div>
<div class="footer">
<MkLink :url="`https://github.com/syuilo/misskey/blob/master/src/docs/${doc}.ja-JP.md`" class="at">{{ $ts.docSource }}</MkLink>
<MkLink :url="`https://github.com/syuilo/misskey/blob/master/src/docs/${lang}/${doc}.md`" class="at">{{ $ts.docSource }}</MkLink>
</div>
</div>
</template>
@@ -45,6 +45,7 @@ export default defineComponent({
title: null,
body: null,
markdown: null,
lang,
}
},

View File

@@ -145,6 +145,46 @@
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $ts._mfm.x2 }}</div>
<div class="_content">
<p>{{ $ts._mfm.x2Description }}</p>
<div class="preview _panel">
<Mfm :text="preview_x2"/>
<MkTextarea v-model:value="preview_x2"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $ts._mfm.x3 }}</div>
<div class="_content">
<p>{{ $ts._mfm.x3Description }}</p>
<div class="preview _panel">
<Mfm :text="preview_x3"/>
<MkTextarea v-model:value="preview_x3"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $ts._mfm.x4 }}</div>
<div class="_content">
<p>{{ $ts._mfm.x4Description }}</p>
<div class="preview _panel">
<Mfm :text="preview_x4"/>
<MkTextarea v-model:value="preview_x4"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $ts._mfm.blur }}</div>
<div class="_content">
<p>{{ $ts._mfm.blurDescription }}</p>
<div class="preview _panel">
<Mfm :text="preview_blur"/>
<MkTextarea v-model:value="preview_blur"><span>MFM</span></MkTextarea>
</div>
</div>
</div>
<div class="_section">
<div class="_title">{{ $ts._mfm.jelly }}</div>
<div class="_content">
@@ -255,6 +295,10 @@ export default defineComponent({
preview_twitch: `[twitch 🍮]`,
preview_spin: `[spin 🍮] [spin.left 🍮] [spin.alternate 🍮]\n[spin.x 🍮] [spin.x,left 🍮] [spin.x,alternate 🍮]\n[spin.y 🍮] [spin.y,left 🍮] [spin.y,alternate 🍮]`,
preview_flip: `[flip ${this.$ts._mfm.dummy}]\n[flip.v ${this.$ts._mfm.dummy}]\n[flip.h,v ${this.$ts._mfm.dummy}]`,
preview_x2: `[x2 🍮]`,
preview_x3: `[x3 🍮]`,
preview_x4: `[x4 🍮]`,
preview_blur: `[blur ${this.$ts._mfm.dummy}]`,
}
},
});

View File

@@ -27,6 +27,9 @@
<FormLink :active="page === 'api'" replace to="/settings/api"><template #icon><Fa :icon="faKey"/></template>API</FormLink>
<FormLink :active="page === 'other'" replace to="/settings/other"><template #icon><Fa :icon="faEllipsisH"/></template>{{ $ts.other }}</FormLink>
</FormGroup>
<FormGroup>
<FormButton @click="clear">{{ $ts.clearCache }}</FormButton>
</FormGroup>
<FormGroup>
<FormButton @click="logout" danger>{{ $ts.logout }}</FormButton>
</FormGroup>
@@ -126,6 +129,11 @@ export default defineComponent({
logout: () => {
signout();
},
clear: () => {
localStorage.removeItem('locale');
localStorage.removeItem('theme');
location.reload();
},
faPalette, faPlug, faUser, faListUl, faLock, faLaugh, faCommentSlash, faMusic, faBell, faCogs, faEllipsisH, faBan, faShareAlt, faLockOpen, faKey, faBoxes, faEnvelope,
};
},

View File

@@ -90,12 +90,25 @@ export default defineComponent({
save() {
this.$store.set('menu', this.splited);
this.reloadAsk();
},
reset() {
this.$store.reset('menu');
this.items = this.$store.state.menu.join('\n');
this.reloadAsk();
},
async reloadAsk() {
const { canceled } = await os.dialog({
type: 'info',
text: this.$ts.reloadToApplySetting,
showCancelButton: true
});
if (canceled) return;
location.reload();
}
},
});
</script>

View File

@@ -8,17 +8,17 @@
<div class="tabs _panel _vMargin">
<div class="left">
<button class="_button tab" @click="() => { src = 'home'; saveSrc(); }" :class="{ active: src === 'home' }" v-tooltip="$ts._timelines.home"><Fa :icon="faHome"/></button>
<button class="_button tab" @click="() => { src = 'local'; saveSrc(); }" :class="{ active: src === 'local' }" v-tooltip="$ts._timelines.local"><Fa :icon="faComments"/></button>
<button class="_button tab" @click="() => { src = 'social'; saveSrc(); }" :class="{ active: src === 'social' }" v-tooltip="$ts._timelines.social"><Fa :icon="faShareAlt"/></button>
<button class="_button tab" @click="() => { src = 'global'; saveSrc(); }" :class="{ active: src === 'global' }" v-tooltip="$ts._timelines.global"><Fa :icon="faGlobe"/></button>
<button class="_button tab" @click="() => { src = 'local'; saveSrc(); }" :class="{ active: src === 'local' }" v-tooltip="$ts._timelines.local" v-if="isLocalTimelineAvailable"><Fa :icon="faComments"/></button>
<button class="_button tab" @click="() => { src = 'social'; saveSrc(); }" :class="{ active: src === 'social' }" v-tooltip="$ts._timelines.social" v-if="isLocalTimelineAvailable"><Fa :icon="faShareAlt"/></button>
<button class="_button tab" @click="() => { src = 'global'; saveSrc(); }" :class="{ active: src === 'global' }" v-tooltip="$ts._timelines.global" v-if="isGlobalTimelineAvailable"><Fa :icon="faGlobe"/></button>
<span class="divider"></span>
<button class="_button tab" @click="() => { src = 'mentions'; saveSrc(); }" :class="{ active: src === 'mentions' }" v-tooltip="$ts.mentions"><Fa :icon="faAt"/><Fa :icon="faCircle" class="i" v-if="$i.hasUnreadMentions"/></button>
<button class="_button tab" @click="() => { src = 'directs'; saveSrc(); }" :class="{ active: src === 'directs' }" v-tooltip="$ts.directNotes"><Fa :icon="faEnvelope"/><Fa :icon="faCircle" class="i" v-if="$i.hasUnreadSpecifiedNotes"/></button>
</div>
<div class="right">
<button class="_button tab" @click="chooseChannel" :class="{ active: src === 'channel' }" v-tooltip="$ts.channel"><Fa :icon="faSatelliteDish"/><Fa :icon="faCircle" class="i" v-if="$i.hasUnreadChannel"/></button>
<button class="_button tab" @click="chooseAntenna" :class="{ active: src === 'antenna' }" v-tooltip="$ts.antennas"><Fa :icon="faSatellite"/><Fa :icon="faCircle" class="i" v-if="$i.hasUnreadAntenna"/></button>
<button class="_button tab" @click="chooseList" :class="{ active: src === 'list' }" v-tooltip="$ts.lists"><Fa :icon="faListUl"/></button>
<button class="_button tab" @click="() => { src = 'directs'; saveSrc(); }" :class="{ active: src === 'directs' }" v-tooltip="$ts.directNotes"><Fa :icon="faEnvelope"/><Fa :icon="faCircle" class="i" v-if="$i.hasUnreadSpecifiedNotes"/></button>
<button class="_button tab" @click="() => { src = 'mentions'; saveSrc(); }" :class="{ active: src === 'mentions' }" v-tooltip="$ts.mentions"><Fa :icon="faAt"/><Fa :icon="faCircle" class="i" v-if="$i.hasUnreadMentions"/></button>
<button class="_button tab" @click="chooseTl"><Fa :icon="faEllipsisH"/></button>
</div>
</div>
<XTimeline ref="tl"
@@ -84,8 +84,12 @@ export default defineComponent({
};
},
meta() {
return this.$instance;
isLocalTimelineAvailable(): boolean {
return !this.$instance.disableLocalTimeline || this.$i.isModerator || this.$i.isAdmin;
},
isGlobalTimelineAvailable(): boolean {
return !this.$instance.disableGlobalTimeline || this.$i.isModerator || this.$i.isAdmin;
},
},
@@ -228,6 +232,9 @@ export default defineComponent({
white-space: nowrap;
overflow: auto;
// 影の都合上
position: relative;
> .right {
margin-left: auto;
}
@@ -269,6 +276,15 @@ export default defineComponent({
animation: blink 1s infinite;
}
}
> .divider {
display: inline-block;
width: 1px;
height: 28px;
vertical-align: middle;
margin: 0 8px;
background: var(--divider);
}
}
}
}

View File

@@ -0,0 +1,307 @@
<template>
<div class="rsqzvsbo" v-if="meta">
<div class="top">
<MkFeaturedPhotos class="bg"/>
<XTimeline class="tl"/>
<div class="shape"></div>
<img src="/assets/misskey.svg" class="misskey"/>
<div class="emojis">
<MkEmoji :normal="true" :no-style="true" emoji="👍"/>
<MkEmoji :normal="true" :no-style="true" emoji="❤"/>
<MkEmoji :normal="true" :no-style="true" emoji="😆"/>
<MkEmoji :normal="true" :no-style="true" emoji="🎉"/>
<MkEmoji :normal="true" :no-style="true" emoji="🍮"/>
</div>
<div class="main _panel">
<div class="bg">
<div class="fade"></div>
</div>
<div class="fg">
<h1>
<img class="logo" v-if="meta.logoImageUrl" :src="meta.logoImageUrl"><span v-else class="text">{{ instanceName }}</span>
</h1>
<div class="about">
<div class="desc" v-html="meta.description || $ts.headlineMisskey"></div>
</div>
<div class="action">
<MkButton @click="signup()" inline primary>{{ $ts.signup }}</MkButton>
<MkButton @click="signin()" inline>{{ $ts.login }}</MkButton>
</div>
<div class="status" v-if="onlineUsersCount && stats">
<div>
<I18n :src="$ts.nUsers" text-tag="span" class="users">
<template #n><b>{{ number(stats.originalUsersCount) }}</b></template>
</I18n>
<I18n :src="$ts.nNotes" text-tag="span" class="notes">
<template #n><b>{{ number(stats.originalNotesCount) }}</b></template>
</I18n>
</div>
<I18n :src="$ts.onlineUsersCount" text-tag="span" class="online">
<template #n><b>{{ onlineUsersCount }}</b></template>
</I18n>
</div>
<button class="_button _acrylic menu" @click="showMenu"><Fa :icon="faEllipsisH"/></button>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { faEllipsisH, faInfoCircle, faQuestionCircle } from '@fortawesome/free-solid-svg-icons';
import { toUnicode } from 'punycode';
import XSigninDialog from '@/components/signin-dialog.vue';
import XSignupDialog from '@/components/signup-dialog.vue';
import MkButton from '@/components/ui/button.vue';
import XNote from '@/components/note.vue';
import MkFeaturedPhotos from '@/components/featured-photos.vue';
import XTimeline from './welcome.timeline.vue';
import { host, instanceName } from '@/config';
import * as os from '@/os';
import number from '@/filters/number';
export default defineComponent({
components: {
MkButton,
XNote,
MkFeaturedPhotos,
XTimeline,
},
data() {
return {
host: toUnicode(host),
instanceName,
meta: null,
stats: null,
tags: [],
onlineUsersCount: null,
faEllipsisH
};
},
created() {
os.api('meta', { detail: true }).then(meta => {
this.meta = meta;
});
os.api('stats').then(stats => {
this.stats = stats;
});
os.api('get-online-users-count').then(res => {
this.onlineUsersCount = res.count;
});
os.api('hashtags/list', {
sort: '+mentionedLocalUsers',
limit: 8
}).then(tags => {
this.tags = tags;
});
},
methods: {
signin() {
os.popup(XSigninDialog, {
autoSet: true
}, {}, 'closed');
},
signup() {
os.popup(XSignupDialog, {
autoSet: true
}, {}, 'closed');
},
showMenu(ev) {
os.modalMenu([{
text: this.$t('aboutX', { x: instanceName }),
icon: faInfoCircle,
action: () => {
os.pageWindow('/about');
}
}, {
text: this.$ts.aboutMisskey,
icon: faInfoCircle,
action: () => {
os.pageWindow('/about-misskey');
}
}, null, {
text: this.$ts.help,
icon: faQuestionCircle,
action: () => {
os.pageWindow('/docs');
}
}], ev.currentTarget || ev.target);
},
number
}
});
</script>
<style lang="scss" scoped>
.rsqzvsbo {
> .top {
display: flex;
text-align: center;
min-height: 100vh;
box-sizing: border-box;
padding: 16px;
> .bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
> .tl {
position: absolute;
top: 0;
bottom: 0;
right: 64px;
margin: auto;
width: 500px;
height: calc(100% - 128px);
overflow: hidden;
-webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 128px, rgba(0,0,0,1) calc(100% - 128px), rgba(0,0,0,0) 100%);
mask-image: linear-gradient(0deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 128px, rgba(0,0,0,1) calc(100% - 128px), rgba(0,0,0,0) 100%);
@media (max-width: 1200px) {
display: none;
}
}
> .shape {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--accent);
clip-path: polygon(0% 0%, 50% 0%, 15% 100%, 0% 100%);
}
> .misskey {
position: absolute;
top: 42px;
left: 42px;
width: 160px;
@media (max-width: 450px) {
width: 130px;
}
}
> .emojis {
position: absolute;
bottom: 32px;
left: 35px;
> * {
margin-right: 8px;
}
@media (max-width: 1200px) {
display: none;
}
}
> .main {
position: relative;
width: min(480px, 100%);
margin: auto auto auto 128px;
box-shadow: 0 12px 32px rgb(0 0 0 / 25%);
@media (max-width: 1200px) {
margin: auto;
}
> .bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 128px;
background-position: center;
background-size: cover;
opacity: 0.75;
> .fade {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 128px;
background: linear-gradient(0deg, var(--panel), var(--X15));
}
}
> .fg {
position: relative;
z-index: 1;
> h1 {
display: block;
margin: 0;
padding: 32px 32px 24px 32px;
> .logo {
vertical-align: bottom;
max-height: 120px;
}
}
> .about {
padding: 0 32px;
}
> .action {
padding: 32px;
> * {
line-height: 28px;
}
}
> .status {
border-top: solid 1px var(--divider);
padding: 32px;
font-size: 90%;
> div {
> span:not(:last-child) {
padding-right: 1em;
margin-right: 1em;
border-right: solid 1px var(--divider);
}
}
> .online {
::v-deep(b) {
color: #41b781;
}
::v-deep(span) {
opacity: 0.7;
}
}
}
> .menu {
position: absolute;
top: 16px;
right: 16px;
width: 32px;
height: 32px;
border-radius: 8px;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,218 @@
<template>
<div class="rsqzvsbo" v-if="meta">
<div class="top">
<MkFeaturedPhotos class="bg"/>
<XTimeline class="tl"/>
<div class="shape"></div>
<div class="main">
<h1>
<img class="logo" v-if="meta.logoImageUrl" :src="meta.logoImageUrl"><span v-else class="text">{{ instanceName }}</span>
</h1>
<div class="about">
<div class="desc" v-html="meta.description || $ts.headlineMisskey"></div>
</div>
<div class="action">
<MkButton class="signup" @click="signup()" inline primary>{{ $ts.signup }}</MkButton>
<MkButton class="signin" @click="signin()" inline>{{ $ts.login }}</MkButton>
</div>
<div class="status" v-if="onlineUsersCount">
<I18n :src="$ts.onlineUsersCount" text-tag="span" class="online">
<template #n><b>{{ onlineUsersCount }}</b></template>
</I18n>
</div>
</div>
<img src="/assets/misskey.svg" class="misskey"/>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { faEllipsisH, faInfoCircle, faQuestionCircle } from '@fortawesome/free-solid-svg-icons';
import { toUnicode } from 'punycode';
import XSigninDialog from '@/components/signin-dialog.vue';
import XSignupDialog from '@/components/signup-dialog.vue';
import MkButton from '@/components/ui/button.vue';
import XNote from '@/components/note.vue';
import MkFeaturedPhotos from '@/components/featured-photos.vue';
import XTimeline from './welcome.timeline.vue';
import { host, instanceName } from '@/config';
import * as os from '@/os';
import number from '@/filters/number';
export default defineComponent({
components: {
MkButton,
XNote,
XTimeline,
MkFeaturedPhotos,
},
data() {
return {
host: toUnicode(host),
instanceName,
meta: null,
stats: null,
tags: [],
onlineUsersCount: null,
faEllipsisH
};
},
created() {
os.api('meta', { detail: true }).then(meta => {
this.meta = meta;
});
os.api('stats').then(stats => {
this.stats = stats;
});
os.api('get-online-users-count').then(res => {
this.onlineUsersCount = res.count;
});
os.api('hashtags/list', {
sort: '+mentionedLocalUsers',
limit: 8
}).then(tags => {
this.tags = tags;
});
},
methods: {
signin() {
os.popup(XSigninDialog, {
autoSet: true
}, {}, 'closed');
},
signup() {
os.popup(XSignupDialog, {
autoSet: true
}, {}, 'closed');
},
showMenu(ev) {
os.modalMenu([{
text: this.$t('aboutX', { x: instanceName }),
icon: faInfoCircle,
action: () => {
os.pageWindow('/about');
}
}, {
text: this.$ts.aboutMisskey,
icon: faInfoCircle,
action: () => {
os.pageWindow('/about-misskey');
}
}, null, {
text: this.$ts.help,
icon: faQuestionCircle,
action: () => {
os.pageWindow('/docs');
}
}], ev.currentTarget || ev.target);
},
number
}
});
</script>
<style lang="scss" scoped>
.rsqzvsbo {
> .top {
min-height: 100vh;
box-sizing: border-box;
> .bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
> .tl {
position: absolute;
top: 0;
bottom: 0;
right: 64px;
margin: auto;
width: 500px;
height: calc(100% - 128px);
overflow: hidden;
-webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 128px, rgba(0,0,0,1) calc(100% - 128px), rgba(0,0,0,0) 100%);
mask-image: linear-gradient(0deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 128px, rgba(0,0,0,1) calc(100% - 128px), rgba(0,0,0,0) 100%);
}
> .shape {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--accent);
clip-path: polygon(0% 0%, 40% 0%, 22% 100%, 0% 100%);
}
> .misskey {
position: absolute;
bottom: 64px;
left: 64px;
width: 160px;
}
> .main {
position: relative;
width: min(490px, 100%);
padding: 64px;
color: #fff;
font-size: 1.1em;
@media (max-width: 1200px) {
margin: auto;
}
> h1 {
display: block;
margin: 0 0 16px 0;
padding: 0;
> .logo {
vertical-align: bottom;
max-height: 100px;
}
}
> .about {
padding: 0;
}
> .action {
margin: 32px 0;
> .signup {
background: var(--panel);
color: var(--fg);
}
> .signin {
background: var(--accent);
color: inherit;
}
}
> .status {
margin: 32px 0;
> .online {
}
}
}
}
}
</style>

View File

@@ -0,0 +1,306 @@
<template>
<div class="rsqzvsbo" v-if="meta">
<div class="top">
<MkFeaturedPhotos class="bg"/>
<div class="fade"></div>
<div class="emojis">
<MkEmoji :normal="true" :no-style="true" emoji="👍"/>
<MkEmoji :normal="true" :no-style="true" emoji="❤"/>
<MkEmoji :normal="true" :no-style="true" emoji="😆"/>
<MkEmoji :normal="true" :no-style="true" emoji="🎉"/>
<MkEmoji :normal="true" :no-style="true" emoji="🍮"/>
</div>
<div class="main">
<img src="/assets/misskey.svg" class="misskey"/>
<div class="form _panel">
<div class="bg">
<div class="fade"></div>
</div>
<div class="fg">
<h1>
<img class="logo" v-if="meta.logoImageUrl" :src="meta.logoImageUrl"><span v-else class="text">{{ instanceName }}</span>
</h1>
<div class="about">
<div class="desc" v-html="meta.description || $ts.headlineMisskey"></div>
</div>
<div class="action">
<MkButton @click="signup()" inline primary>{{ $ts.signup }}</MkButton>
<MkButton @click="signin()" inline>{{ $ts.login }}</MkButton>
</div>
<div class="status" v-if="onlineUsersCount && stats">
<div>
<I18n :src="$ts.nUsers" text-tag="span" class="users">
<template #n><b>{{ number(stats.originalUsersCount) }}</b></template>
</I18n>
<I18n :src="$ts.nNotes" text-tag="span" class="notes">
<template #n><b>{{ number(stats.originalNotesCount) }}</b></template>
</I18n>
</div>
<I18n :src="$ts.onlineUsersCount" text-tag="span" class="online">
<template #n><b>{{ onlineUsersCount }}</b></template>
</I18n>
</div>
<button class="_button _acrylic menu" @click="showMenu"><Fa :icon="faEllipsisH"/></button>
</div>
</div>
<nav class="nav">
<MkA to="/announcements">{{ $ts.announcements }}</MkA>
<MkA to="/explore">{{ $ts.explore }}</MkA>
<MkA to="/channels">{{ $ts.channel }}</MkA>
<MkA to="/featured">{{ $ts.featured }}</MkA>
</nav>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { faEllipsisH, faInfoCircle, faQuestionCircle } from '@fortawesome/free-solid-svg-icons';
import { toUnicode } from 'punycode';
import XSigninDialog from '@/components/signin-dialog.vue';
import XSignupDialog from '@/components/signup-dialog.vue';
import MkButton from '@/components/ui/button.vue';
import XNote from '@/components/note.vue';
import MkFeaturedPhotos from '@/components/featured-photos.vue';
import XTimeline from './welcome.timeline.vue';
import { host, instanceName } from '@/config';
import * as os from '@/os';
import number from '@/filters/number';
export default defineComponent({
components: {
MkButton,
XNote,
MkFeaturedPhotos,
XTimeline,
},
data() {
return {
host: toUnicode(host),
instanceName,
meta: null,
stats: null,
tags: [],
onlineUsersCount: null,
faEllipsisH
};
},
created() {
os.api('meta', { detail: true }).then(meta => {
this.meta = meta;
});
os.api('stats').then(stats => {
this.stats = stats;
});
os.api('get-online-users-count').then(res => {
this.onlineUsersCount = res.count;
});
os.api('hashtags/list', {
sort: '+mentionedLocalUsers',
limit: 8
}).then(tags => {
this.tags = tags;
});
},
methods: {
signin() {
os.popup(XSigninDialog, {
autoSet: true
}, {}, 'closed');
},
signup() {
os.popup(XSignupDialog, {
autoSet: true
}, {}, 'closed');
},
showMenu(ev) {
os.modalMenu([{
text: this.$t('aboutX', { x: instanceName }),
icon: faInfoCircle,
action: () => {
os.pageWindow('/about');
}
}, {
text: this.$ts.aboutMisskey,
icon: faInfoCircle,
action: () => {
os.pageWindow('/about-misskey');
}
}, null, {
text: this.$ts.help,
icon: faQuestionCircle,
action: () => {
os.pageWindow('/docs');
}
}], ev.currentTarget || ev.target);
},
number
}
});
</script>
<style lang="scss" scoped>
.rsqzvsbo {
> .top {
display: flex;
text-align: center;
min-height: 100vh;
box-sizing: border-box;
padding: 16px;
> .bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
> .fade {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.25);
}
> .emojis {
position: absolute;
bottom: 32px;
left: 35px;
> * {
margin-right: 8px;
}
@media (max-width: 1200px) {
display: none;
}
}
> .main {
position: relative;
width: min(460px, 100%);
margin: auto;
> .misskey {
width: 150px;
margin-bottom: 16px;
@media (max-width: 450px) {
width: 130px;
}
}
> .form {
position: relative;
box-shadow: 0 12px 32px rgb(0 0 0 / 25%);
> .bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 128px;
background-position: center;
background-size: cover;
opacity: 0.75;
> .fade {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 128px;
background: linear-gradient(0deg, var(--panel), var(--X15));
}
}
> .fg {
position: relative;
z-index: 1;
> h1 {
display: block;
margin: 0;
padding: 32px 32px 24px 32px;
> .logo {
vertical-align: bottom;
max-height: 120px;
}
}
> .about {
padding: 0 32px;
}
> .action {
padding: 32px;
> * {
line-height: 28px;
}
}
> .status {
border-top: solid 1px var(--divider);
padding: 32px;
font-size: 90%;
> div {
> span:not(:last-child) {
padding-right: 1em;
margin-right: 1em;
border-right: solid 1px var(--divider);
}
}
> .online {
::v-deep(b) {
color: #41b781;
}
::v-deep(span) {
opacity: 0.7;
}
}
}
> .menu {
position: absolute;
top: 16px;
right: 16px;
width: 32px;
height: 32px;
border-radius: 8px;
}
}
}
> .nav {
position: relative;
z-index: 2;
margin-top: 20px;
color: #fff;
text-shadow: 0 0 8px black;
> *:not(:last-child) {
margin-right: 1em;
}
}
}
}
}
</style>

View File

@@ -1,181 +0,0 @@
<template>
<div class="rsqzvsbo _section" v-if="meta">
<div class="overview _monospace" v-if="stats">
<div class="stats">
<div><span>Users</span><span>{{ number(stats.originalUsersCount) }}</span></div>
<div><span>Notes</span><span>{{ number(stats.originalNotesCount) }}</span></div>
<div><span>Reactions</span><span>{{ number(stats.reactionsCount) }}</span></div>
</div>
<div class="tags">
<MkA class="tag" v-for="tag in tags" :to="`/tags/${encodeURIComponent(tag.tag)}`">#{{ tag.tag }}</MkA>
</div>
</div>
<template v-if="meta.pinnedClipId">
<h2># {{ $ts.pinnedNotes }}</h2>
<MkPagination :pagination="clipPagination" #default="{items}">
<XNote class="kmkqjgkl" v-for="note in items" :note="note" :key="note.id"/>
</MkPagination>
</template>
<template v-else>
<h2># {{ $ts.featured }}</h2>
<MkPagination :pagination="featuredPagination" #default="{items}">
<XNote class="kmkqjgkl" v-for="note in items" :note="note" :key="note.id"/>
</MkPagination>
</template>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { toUnicode } from 'punycode';
import XSigninDialog from '@/components/signin-dialog.vue';
import XSignupDialog from '@/components/signup-dialog.vue';
import MkButton from '@/components/ui/button.vue';
import XNote from '@/components/note.vue';
import MkPagination from '@/components/ui/pagination.vue';
import { host, instanceName } from '@/config';
import * as os from '@/os';
import number from '@/filters/number';
export default defineComponent({
components: {
MkButton,
XNote,
MkPagination,
},
data() {
return {
host: toUnicode(host),
instanceName,
meta: null,
stats: null,
tags: [],
clipPagination: {
endpoint: 'clips/notes',
limit: 10,
params: () => ({
clipId: this.meta.pinnedClipId,
})
},
featuredPagination: {
endpoint: 'notes/featured',
limit: 10,
offsetMode: true
},
};
},
created() {
os.api('meta', { detail: true }).then(meta => {
this.meta = meta;
});
os.api('stats').then(stats => {
this.stats = stats;
});
os.api('hashtags/list', {
sort: '+mentionedLocalUsers',
limit: 8
}).then(tags => {
this.tags = tags;
});
},
methods: {
signin() {
os.popup(XSigninDialog, {
autoSet: true
}, {}, 'closed');
},
signup() {
os.popup(XSignupDialog, {
autoSet: true
}, {}, 'closed');
},
number
}
});
</script>
<style lang="scss" scoped>
.rsqzvsbo {
text-align: center;
> h2 {
display: inline-block;
color: #fff;
margin: 16px;
padding: 8px 12px;
background: rgba(0, 0, 0, 0.5);
}
> .overview {
> .stats, > .tags {
display: inline-block;
vertical-align: top;
width: 530px;
padding: 32px;
margin: 16px;
box-sizing: border-box;
@media (max-width: 800px) {
display: block;
width: 100%;
margin: 12px 0;
}
}
> .stats {
background: var(--accent);
border-radius: 12px;
color: #fff;
font-size: 1.5em;
> div {
display: flex;
> span:first-child {
opacity: 0.7;
font-weight: bold;
}
> span:last-child {
margin-left: auto;
}
}
}
> .tags {
background: var(--panel);
border-radius: 12px;
color: var(--fg);
font-size: 1.5em;
> .tag {
margin-right: 1em;
}
}
}
}
.kmkqjgkl {
display: inline-block;
vertical-align: middle;
width: 530px;
margin: 16px;
box-sizing: border-box;
text-align: left;
box-shadow: 0 6px 46px rgb(0 0 0 / 25%);
border-radius: 12px;
@media (max-width: 800px) {
display: block;
width: 100%;
margin: 12px 0;
}
}
</style>

View File

@@ -0,0 +1,51 @@
<template>
<div class="civpbkhh">
<div v-for="note in notes" class="note">
<div class="content _panel">
{{ note.text }}
</div>
<XReactionsViewer :note="note" ref="reactionsViewer"/>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import XReactionsViewer from '@/components/reactions-viewer.vue';
import * as os from '@/os';
export default defineComponent({
components: {
XReactionsViewer
},
data() {
return {
notes: [],
}
},
created() {
os.api('notes/featured').then(notes => {
this.notes = notes;
});
}
});
</script>
<style lang="scss" scoped>
.civpbkhh {
text-align: right;
> .note {
margin: 16px 0 16px auto;
> .content {
padding: 16px;
margin: 0 0 0 auto;
max-width: max-content;
border-radius: 16px;
}
}
}
</style>

View File

@@ -8,7 +8,7 @@
<script lang="ts">
import { defineComponent } from 'vue';
import XSetup from './welcome.setup.vue';
import XEntrance from './welcome.entrance.vue';
import XEntrance from './welcome.entrance.c.vue';
import { instanceName } from '@/config';
import * as os from '@/os';

View File

@@ -62,7 +62,6 @@
error: '#ec4137',
warn: '#ecb637',
htmlThemeColor: '@bg',
X1: ':alpha<0<@bg',
X2: ':darken<2<@panel',
X3: 'rgba(255, 255, 255, 0.05)',
X4: 'rgba(255, 255, 255, 0.1)',

View File

@@ -62,7 +62,6 @@
error: '#ec4137',
warn: '#ecb637',
htmlThemeColor: '@bg',
X1: ':alpha<0<@bg',
X2: ':darken<2<@panel',
X3: 'rgba(0, 0, 0, 0.05)',
X4: 'rgba(0, 0, 0, 0.1)',

View File

@@ -8,7 +8,7 @@
<!-- sectionを利用しているのはdeck.vue側でcolumnに対してfirst-of-typeを効かせるため -->
<section v-if="ids.length > 1"
class="folder column"
:style="{ width: Math.max(...columns.filter(c => ids.includes(c.id)).map(c => c.width)) + 'px' }"
:style="columns.filter(c => ids.includes(c.id)).some(c => c.flexible) ? { flex: 1, minWidth: '350px' } : { width: Math.max(...columns.filter(c => ids.includes(c.id)).map(c => c.width)) + 'px' }"
>
<DeckColumnCore v-for="id in ids" :ref="id" :key="id" :column="columns.find(c => c.id === id)" :is-stacked="true" @parent-focus="moveFocus(id, $event)"/>
</section>

View File

@@ -191,6 +191,7 @@ export default defineComponent({
} : undefined, null, {
icon: faTrashAlt,
text: this.$ts.remove,
danger: true,
action: () => {
removeColumn(this.column.id);
}

View File

@@ -7,7 +7,7 @@
<router-view v-slot="{ Component }">
<transition>
<keep-alive :include="['timeline']">
<component :is="Component" :ref="changePage"/>
<component :is="Component" :ref="changePage" @contextmenu.stop="onContextmenu"/>
</keep-alive>
</transition>
</router-view>
@@ -16,10 +16,12 @@
<script lang="ts">
import { defineComponent } from 'vue';
import { faWindowMaximize } from '@fortawesome/free-solid-svg-icons';
import XColumn from './column.vue';
import XNotes from '@/components/notes.vue';
import XHeader from '@/ui/_common_/header.vue';
import { deckStore } from '@/ui/deck/deck-store';
import * as os from '@/os';
export default defineComponent({
components: {
@@ -43,7 +45,6 @@ export default defineComponent({
return {
deckStore,
pageInfo: null,
pageKey: 0,
}
},
@@ -54,6 +55,21 @@ export default defineComponent({
this.pageInfo = page.INFO;
}
},
onContextmenu(e) {
if (['INPUT', 'TEXTAREA'].includes(e.target.tagName) || e.target.attributes['contenteditable']) return;
const path = this.$route.path;
os.contextMenu([{
type: 'label',
text: path,
}, {
icon: faWindowMaximize,
text: this.$ts.openInWindow,
action: () => {
os.pageWindow(path);
}
}], e);
},
}
});
</script>

View File

@@ -114,7 +114,9 @@ export default defineComponent({
<style lang="scss" scoped>
.wtdtxvec {
padding-top: 1px; // ウィジェットのbox-shadowを利用した1px borderを隠さないようにするため
._panel {
box-shadow: none;
}
> header {
padding: 16px;

View File

@@ -2,7 +2,7 @@
<div class="mk-app" :class="{ wallpaper }">
<XSidebar ref="nav" class="sidebar"/>
<div class="contents" ref="contents" :class="{ withHeader: $store.state.titlebar }" @contextmenu.prevent.stop="onContextmenu">
<div class="contents" ref="contents" :class="{ withHeader: $store.state.titlebar }" @contextmenu.stop="onContextmenu">
<header v-if="$store.state.titlebar" class="header" ref="header" @click="onHeaderClick">
<XHeader :info="pageInfo"/>
</header>
@@ -29,6 +29,7 @@
<div class="buttons" :class="{ navHidden }">
<button class="button nav _button" @click="showNav" ref="navButton"><Fa :icon="faBars"/><i v-if="navIndicated"><Fa :icon="faCircle"/></i></button>
<button class="button home _button" @click="$route.name === 'index' ? top() : $router.push('/')"><Fa :icon="faHome"/></button>
<button class="button notifications _button" @click="$router.push('/my/notifications')"><Fa :icon="faBell"/><i v-if="$i.hasUnreadNotification"><Fa :icon="faCircle"/></i></button>
<button class="button widget _button" @click="widgetsShowing = true"><Fa :icon="faLayerGroup"/></button>
<button class="button post _button" @click="post"><Fa :icon="faPencilAlt"/></button>
@@ -53,10 +54,10 @@
</template>
<script lang="ts">
import { defineComponent, defineAsyncComponent, markRaw } from 'vue';
import { defineComponent, defineAsyncComponent } 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 { instanceName } from '@/config';
import { StickySidebar } from '@/scripts/sticky-sidebar';
import XSidebar from '@/components/sidebar.vue';
import XCommon from './_common_/common.vue';
@@ -86,8 +87,6 @@ export default defineComponent({
data() {
return {
host: host,
pageKey: 0,
pageInfo: null,
isDesktop: window.innerWidth >= DESKTOP_THRESHOLD,
menuDef: sidebarDef,
@@ -108,12 +107,6 @@ export default defineComponent({
}
},
watch: {
$route(to, from) {
this.pageKey++;
},
},
created() {
document.documentElement.style.overflowY = 'scroll';
@@ -154,6 +147,7 @@ export default defineComponent({
if (page == null) return;
if (page.INFO) {
this.pageInfo = page.INFO;
document.title = `${this.pageInfo.title} | ${instanceName}`;
}
},
@@ -193,6 +187,7 @@ export default defineComponent({
},
onContextmenu(e) {
if (['INPUT', 'TEXTAREA'].includes(e.target.tagName) || e.target.attributes['contenteditable']) return;
const path = this.$route.path;
os.contextMenu([{
type: 'label',
@@ -339,15 +334,13 @@ export default defineComponent({
position: fixed;
z-index: 1000;
bottom: 0;
padding: 0 32px 32px 32px;
padding: 16px;
display: flex;
width: 100%;
box-sizing: border-box;
background: linear-gradient(0deg, var(--bg), var(--X1));
@media (max-width: 500px) {
padding: 0 16px 16px 16px;
}
-webkit-backdrop-filter: blur(32px);
backdrop-filter: blur(32px);
background-color: var(--header);
&:not(.navHidden) {
display: none;
@@ -355,15 +348,26 @@ export default defineComponent({
> .button {
position: relative;
flex: 1;
padding: 0;
margin: auto;
width: 64px;
height: 64px;
border-radius: 100%;
box-shadow: 0 3px 5px -1px rgba(0, 0, 0, 0.2), 0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12);
border-radius: 8px;
background: var(--panel);
color: var(--fg);
&:not(:last-child) {
margin-right: 12px;
}
@media (max-width: 400px) {
height: 60px;
&:not(:last-child) {
margin-right: 8px;
}
}
&:hover {
background: var(--X2);
}

View File

@@ -63,7 +63,6 @@ export default defineComponent({
return {
host,
instanceName,
pageKey: 0,
pageInfo: null,
meta: null,
narrow: window.innerWidth < 1280,
@@ -88,12 +87,6 @@ export default defineComponent({
},
},
watch: {
$route(to, from) {
this.pageKey++;
},
},
created() {
document.documentElement.style.overflowY = 'scroll';

View File

@@ -1,13 +1,13 @@
<template>
<div class="mk-app" :style="{ backgroundImage: root ? `url(${ $instance.backgroundImageUrl })` : 'none' }">
<div class="mk-app">
<a v-if="root" href="https://github.com/syuilo/misskey" target="_blank" class="github-corner" aria-label="View source on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:var(--panel); color:var(--fg); position: fixed; z-index: 10; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>
<div class="side" v-if="!narrow">
<XKanban class="kanban" full :transparent="root" :powered-by="root"/>
<div class="side" v-if="!narrow && !root">
<XKanban class="kanban" full/>
</div>
<div class="main">
<XKanban class="banner" :full="root" :transparent="root" :powered-by="root" v-if="narrow"/>
<XKanban class="banner" :powered-by="root" v-if="narrow && !root"/>
<div class="contents">
<XHeader class="header" :info="pageInfo" v-if="!root"/>
@@ -76,7 +76,6 @@ export default defineComponent({
return {
host,
instanceName,
pageKey: 0,
pageInfo: null,
meta: null,
showMenu: false,
@@ -106,14 +105,8 @@ export default defineComponent({
},
},
watch: {
$route(to, from) {
this.pageKey++;
},
},
created() {
document.documentElement.style.overflowY = 'scroll';
//document.documentElement.style.overflowY = 'scroll';
os.api('meta', { detail: true }).then(meta => {
this.meta = meta;

View File

@@ -38,18 +38,11 @@ export default defineComponent({
data() {
return {
host: host,
pageKey: 0,
pageInfo: null,
faLayerGroup, faBars, faBell, faHome, faCircle,
};
},
watch: {
$route(to, from) {
this.pageKey++;
},
},
created() {
document.documentElement.style.overflowY = 'scroll';
},

View File

@@ -14,6 +14,7 @@ export default function(app: App) {
app.component('MkwFederation', defineAsyncComponent(() => import('./federation.vue')));
app.component('MkwPostForm', defineAsyncComponent(() => import('./post-form.vue')));
app.component('MkwSlideshow', defineAsyncComponent(() => import('./slideshow.vue')));
app.component('MkwOnlineUsers', defineAsyncComponent(() => import('./online-users.vue')));
app.component('MkwButton', defineAsyncComponent(() => import('./button.vue')));
}
@@ -31,5 +32,6 @@ export const widgets = [
'federation',
'postForm',
'slideshow',
'onlineUsers',
'button',
];

View File

@@ -0,0 +1,67 @@
<template>
<div class="mkw-onlineUsers" :class="{ _panel: !props.transparent, pad: !props.transparent }">
<I18n v-if="onlineUsersCount" :src="$ts.onlineUsersCount" text-tag="span" class="text">
<template #n><b>{{ onlineUsersCount }}</b></template>
</I18n>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import define from './define';
import * as os from '@/os';
const widget = define({
name: 'onlineUsers',
props: () => ({
transparent: {
type: 'boolean',
default: true,
},
})
});
export default defineComponent({
extends: widget,
data() {
return {
onlineUsersCount: null,
clock: null,
};
},
created() {
this.tick();
this.clock = setInterval(this.tick, 1000 * 15);
},
beforeUnmount() {
clearInterval(this.clock);
},
methods: {
tick() {
os.api('get-online-users-count').then(res => {
this.onlineUsersCount = res.count;
});
}
}
});
</script>
<style lang="scss" scoped>
.mkw-onlineUsers {
text-align: center;
&.pad {
padding: 16px 0;
}
> .text {
::v-deep(b) {
color: #41b781;
}
::v-deep(span) {
opacity: 0.7;
}
}
}
</style>

View File

@@ -0,0 +1,4 @@
# AiScript
## 関数
デフォルトで値渡しです。

58
src/docs/ht-HT/api.md Normal file
View File

@@ -0,0 +1,58 @@
# Misskey API
MisskeyAPIを使ってMisskeyクライアント、Misskey連携Webサービス、Bot等(以下「アプリケーション」と呼びます)を開発できます。 ストリーミングAPIもあるので、リアルタイム性のあるアプリケーションを作ることも可能です。
APIを使い始めるには、まずアクセストークンを取得する必要があります。 このドキュメントでは、アクセストークンを取得する手順を説明した後、基本的なAPIの使い方を説明します。
## アクセストークンの取得
基本的に、APIはリクエストにはアクセストークンが必要となります。 APIにリクエストするのが自分自身なのか、不特定の利用者に使ってもらうアプリケーションなのかによって取得手順は異なります。
* 前者の場合: [「自分自身のアクセストークンを手動発行する」](#自分自身のアクセストークンを手動発行する)に進む
* 後者の場合: [「アプリケーション利用者にアクセストークンの発行をリクエストする」](#アプリケーション利用者にアクセストークンの発行をリクエストする)に進む
### 自分自身のアクセストークンを手動発行する
「設定 > API」で、自分のアクセストークンを発行できます。
[「APIの使い方」へ進む](#APIの使い方)
### アプリケーション利用者にアクセストークンの発行をリクエストする
アプリケーション利用者のアクセストークンを取得するには、以下の手順で発行をリクエストします。
#### Step 1
UUIDを生成する。以後これをセッションIDと呼びます。
> このセッションIDは毎回生成し、使いまわさないようにしてください。
#### Step 2
`{_URL_}/miauth/{session}`をユーザーのブラウザで表示させる。`{session}`の部分は、セッションIDに置き換えてください。
> 例: `{_URL_}/miauth/c1f6d42b-468b-4fd2-8274-e58abdedef6f`
表示する際、URLにクエリパラメータとしていくつかのオプションを設定できます:
* `name` ... アプリケーション名
* > 例: `MissDeck`
* `icon` ... アプリケーションのアイコン画像URL
* > 例: `https://missdeck.example.com/icon.png`
* `callback` ... 認証が終わった後にリダイレクトするURL
* > 例: `https://missdeck.example.com/callback`
* リダイレクト時には、`session`というクエリパラメータでセッションIDが付きます
* `permission` ... アプリケーションが要求する権限
* > 例: `write:notes,write:following,read:drive`
* 要求する権限を`,`で区切って列挙します
* どのような権限があるかは[APIリファレンス](/api-doc)で確認できます
#### Step 3
ユーザーが発行を許可した後、`{_URL_}/api/miauth/{session}/check`にPOSTリクエストすると、レスポンスとしてアクセストークンを含むJSONが返ります。
レスポンスに含まれるプロパティ:
* `token` ... ユーザーのアクセストークン
* `user` ... ユーザーの情報
[「APIの使い方」へ進む](#APIの使い方)
## APIの使い方
**APIはすべてPOSTで、リクエスト/レスポンスともにJSON形式です。RESTではありません。** アクセストークンは、`i`というパラメータ名でリクエストに含めます。
* [APIリファレンス](/api-doc)
* [ストリーミングAPI](./stream)

View File

@@ -0,0 +1,74 @@
# プラグインの作成
Misskey Webクライアントのプラグイン機能を使うと、クライアントを拡張し、様々な機能を追加できます。 ここではプラグインの作成にあたってのメタデータ定義や、AiScript APIリファレンスを掲載します。
## メタデータ
プラグインは、AiScriptのメタデータ埋め込み機能を使って、デフォルトとしてプラグインのメタデータを定義する必要があります。 メタデータは次のプロパティを含むオブジェクトです。
### name
プラグイン名
### author
プラグイン作者
### version
プラグインバージョン。数値を指定してください。
### description
プラグインの説明
### permissions
プラグインが要求する権限。MisskeyAPIにリクエストする際に用いられます。
### config
プラグインの設定情報を表すオブジェクト。 キーに設定名、値に以下のプロパティを含めます。
#### type
設定値の種類を表す文字列。以下から選択します。 string number boolean
#### label
ユーザーに表示する設定名
#### description
設定の説明
#### default
設定のデフォルト値
## APIリファレンス
AiScript標準で組み込まれているAPIは掲載しません。
### Mk:dialog(title text type)
ダイアログを表示します。typeには以下の値が設定できます。 info success warn error question 省略すると info になります。
### Mk:confirm(title text type)
確認ダイアログを表示します。typeには以下の値が設定できます。 info success warn error question 省略すると question になります。 ユーザーが"OK"を選択した場合は true を、"キャンセル"を選択した場合は false が返ります。
### Mk:api(endpoint params)
Misskey APIにリクエストします。第一引数にエンドポイント名、第二引数にパラメータオブジェクトを渡します。
### Mk:save(key value)
任意の値に任意の名前を付けて永続化します。永続化した値は、AiScriptコンテキストが終了しても残り、Mk:loadで読み取ることができます。
### Mk:load(key)
Mk:saveで永続化した指定の名前の値を読み取ります。
### Plugin:register_post_form_action(title fn)
投稿フォームにアクションを追加します。第一引数にアクション名、第二引数にアクションが選択された際のコールバック関数を渡します。 コールバック関数には、第一引数に投稿フォームオブジェクトが渡されます。
### Plugin:register_note_action(title fn)
ノートメニューに項目を追加します。第一引数に項目名、第二引数に項目が選択された際のコールバック関数を渡します。 コールバック関数には、第一引数に対象のノートオブジェクトが渡されます。
### Plugin:register_user_action(title fn)
ユーザーメニューに項目を追加します。第一引数に項目名、第二引数に項目が選択された際のコールバック関数を渡します。 コールバック関数には、第一引数に対象のユーザーオブジェクトが渡されます。
### Plugin:register_note_view_interruptor(fn)
UIに表示されるート情報を書き換えます。 コールバック関数には、第一引数に対象のノートオブジェクトが渡されます。 コールバック関数の返り値でノートが書き換えられます。
### Plugin:register_note_post_interruptor(fn)
ノート投稿時にノート情報を書き換えます。 コールバック関数には、第一引数に対象のノートオブジェクトが渡されます。 コールバック関数の返り値でノートが書き換えられます。
### Plugin:open_url(url)
第一引数に渡されたURLをブラウザの新しいタブで開きます。
### Plugin:config
プラグインの設定が格納されるオブジェクト。プラグイン定義のconfigで設定したキーで値が入ります。

View File

@@ -0,0 +1,2 @@
# カスタム絵文字
カスタム絵文字は、インスタンスで用意された画像を絵文字のように使える機能です。 ノート、リアクション、チャット、自己紹介、名前などの場所で使うことができます。 カスタム絵文字をそれらの場所で使うには、絵文字ピッカーボタン(ある場合)を押すか、`:`を入力して絵文字サジェストを表示します。 テキスト内に`:foo:`のような形式の文字列が見つかると、`foo`の部分がカスタム絵文字名と解釈され、表示時には対応したカスタム絵文字に置き換わります。

18
src/docs/ht-HT/deck.md Normal file
View File

@@ -0,0 +1,18 @@
# デッキ
デッキは利用可能なUIのひとつです。「カラム」と呼ばれるビューを複数並べて表示させることで、カスタマイズ性が高く、情報量の多いUIが構築できることが特徴です。
## カラムの追加
デッキの背景を右クリックし、「カラムを追加」して任意のカラムを追加できます。
## カラムの移動
カラムは、ドラッグアンドドロップで他のカラムと位置を入れ替えることが出来るほか、カラムメニュー(カラムのヘッダー右クリック)から位置を移動させることもできます。
## カラムの水平分割
カラムは左右だけでなく、上下に並べることもできます。 カラムメニューを開き、「左に重ねる」を選択すると、左のカラムの下に現在のカラムが移動します。 上下分割を解除するには、カラムメニューの「右に出す」を選択します。
## カラムの設定
カラムメニューの「編集」を選択するとカラムの設定を編集できます。カラムの名前を変えたり、幅を変えたりできます。
## デッキの設定
デッキに関する設定は、[settings/deck](/settings/deck)で行えます。

2
src/docs/ht-HT/follow.md Normal file
View File

@@ -0,0 +1,2 @@
# フォロー
ユーザーをフォローすると、タイムラインにそのユーザーの投稿が表示されるようになります。ただし、他のユーザーに対する返信は含まれません。 ユーザーをフォローするには、ユーザーページの「フォロー」ボタンをクリックします。フォローを解除するには、もう一度クリックします。

View File

@@ -0,0 +1,68 @@
# キーボードショートカット
## グローバル
これらのショートカットは基本的にどこでも使えます。
<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">S</kbd></td><td>検索</td><td><b>S</b>earch</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">R</kbd></td><td>返信フォームを開く</td><td><b>R</b>eply</td></tr>
<tr><td><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">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">F</kbd>, <kbd class="key">B</kbd></td><td>お気に入りに登録</td><td><b>F</b>avorite, <b>B</b>ookmark</td></tr>
<tr><td><kbd class="key">Del</kbd>, <kbd class="group"><kbd class="key">Ctrl</kbd> + <kbd class="key">D</kbd></kbd></td><td>投稿を削除</td><td><b>D</b>elete</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>

2
src/docs/ht-HT/mfm.md Normal file
View File

@@ -0,0 +1,2 @@
# MFM
MFMは、Misskey Flavored Markdownの略で、Misskeyの様々な場所で使用できる専用のマークアップ言語です。 MFMで使用可能な構文は[MFMチートシート](/mfm-cheat-sheet)で確認できます。

13
src/docs/ht-HT/mute.md Normal file
View File

@@ -0,0 +1,13 @@
# ミュート
ユーザーをミュートすると、そのユーザーに関する次のコンテンツがMisskeyに表示されなくなります:
* タイムラインや投稿の検索結果内の、そのユーザーの投稿(およびそれらの投稿に対する返信やRenote)
* そのユーザーからの通知
* メッセージ履歴一覧内の、そのユーザーとのメッセージ履歴
ユーザーをミュートするには、対象のユーザーのユーザーページに表示されている「ミュート」ボタンを押します。
ミュートを行ったことは相手に通知されず、ミュートされていることを知ることもできません。
設定>ミュート から、自分がミュートしているユーザー一覧を確認することができます。

10
src/docs/ht-HT/pages.md Normal file
View File

@@ -0,0 +1,10 @@
# Pages
## 変数
変数を使うことで動的なページを作成できます。テキスト内で <b>{ 変数名 }</b> と書くとそこに変数の値を埋め込めます。例えば <b>Hello { thing } world!</b> というテキストで、変数(thing)の値が <b>ai</b> だった場合、テキストは <b>Hello ai world!</b> になります。
変数の評価(値を算出すること)は上から下に行われるので、ある変数の中で自分より下の変数を参照することはできません。例えば上から <b>A、B、C</b> と3つの変数を定義したとき、<b>C</b>の中で<b>A</b><b>B</b>を参照することはできますが、<b>A</b>の中で<b>B</b><b>C</b>を参照することはできません。
ユーザーからの入力を受け取るには、ページに「ユーザー入力」ブロックを設置し、「変数名」に入力を格納したい変数名を設定します(変数は自動で作成されます)。その変数を使ってユーザー入力に応じた動作を行えます。
関数を使うと、値の算出処理を再利用可能な形にまとめることができます。関数を作るには、「関数」タイプの変数を作成します。関数にはスロット(引数)を設定することができ、スロットの値は関数内で変数として利用可能です。また、関数を引数に取る関数(高階関数と呼ばれます)も存在します。関数は予め定義しておくほかに、このような高階関数のスロットに即席でセットすることもできます。

View File

@@ -0,0 +1,11 @@
# リアクション
他の人のノートに、絵文字を付けて簡単にあなたの反応を伝えられる機能です。 リアクションするには、ノートの + アイコンをクリックしてピッカーを表示し、絵文字を選択します。 リアクションには[カスタム絵文字](./custom-emoji)も使用できます。
## リアクションピッカーのカスタマイズ
ピッカーに表示される絵文字を自分好みにカスタマイズすることができます。 設定の「リアクション」で設定します。
## リモート投稿へのリアクションについて
リアクションはMisskeyオリジナルの機能であるため、リモートインスタンスがMisskeyでない限りは、ほとんどの場合「Like」としてアクティビティが送信されます。一般的にはLikeは「お気に入り」として実装されているようです。 また、相手がMisskeyであったとしても、カスタム絵文字リアクションは伝わらず、自動的に「👍」等にフォールバックされます。
## リモートからのリアクションについて
リモートから「Like」アクティビティを受信したとき、Misskeyでは「👍」のリアクションとして解釈されます。

View File

@@ -0,0 +1,160 @@
# MisskeyリバーシBotの開発
Misskeyのリバーシ機能に対応したBotの開発方法をここに記します。
1. `games/reversi`ストリームに以下のパラメータを付けて接続する:
* `i`: botアカウントのAPIキー
2. 対局への招待が来たら、ストリームから`invited`イベントが流れてくる
* イベントの中身に、`parent`という名前で対局へ誘ってきたユーザーの情報が含まれている
3. `games/reversi/match`へ、`user_id`として`parent``id`が含まれたリクエストを送信する
4. 上手くいくとゲーム情報が返ってくるので、`games/reversi-game`ストリームへ、以下のパラメータを付けて接続する:
* `i`: botアカウントのAPIキー
* `game`: `game``id`
5. この間、相手がゲームの設定を変更するとその都度`update-settings`イベントが流れてくるので、必要であれば何かしらの処理を行う
6. 設定に満足したら、`{ type: 'accept' }`メッセージをストリームに送信する
7. ゲームが開始すると、`started`イベントが流れてくる
* イベントの中身にはゲーム情報が含まれている
8. 石を打つには、ストリームに`{ type: 'set', pos: <位置> }`を送信する(位置の計算方法は後述)
9. 相手または自分が石を打つと、ストリームから`set`イベントが流れてくる
* `color`として石の色が含まれている
* `pos`として位置情報が含まれている
## 位置の計算法
8x8のマップを考える場合、各マスの位置(インデックスと呼びます)は次のようになっています:
```
+--+--+--+--+--+--+--+--+
| 0| 1| 2| 3| 4| 5| 6| 7|
+--+--+--+--+--+--+--+--+
| 8| 9|10|11|12|13|14|15|
+--+--+--+--+--+--+--+--+
|16|17|18|19|20|21|22|23|
...
```
### X,Y座標 から インデックス に変換する
```
pos = x + (y * mapWidth)
```
`mapWidth`は、ゲーム情報の`map`から、次のようにして計算できます:
```
mapWidth = map[0].length
```
### インデックス から X,Y座標 に変換する
```
x = pos % mapWidth
y = Math.floor(pos / mapWidth)
```
## マップ情報
マップ情報は、ゲーム情報の`map`に入っています。 文字列の配列になっており、ひとつひとつの文字がマス情報を表しています。 それをもとにマップのデザインを知る事が出来ます:
* `(スペース)` ... マス無し
* `-` ... マス
* `b` ... 初期配置される黒石
* `w` ... 初期配置される白石
例えば、4*4の次のような単純なマップがあるとします:
```text
+---+---+---+---+
| | | | |
+---+---+---+---+
| | ○ | ● | |
+---+---+---+---+
| | ● | ○ | |
+---+---+---+---+
| | | | |
+---+---+---+---+
```
この場合、マップデータはこのようになります:
```javascript
['----', '-wb-', '-bw-', '----']
```
## ユーザーにフォームを提示して対話可能Botを作成する
ユーザーとのコミュニケーションを行うため、ゲームの設定画面でユーザーにフォームを提示することができます。 例えば、Botの強さをユーザーが設定できるようにする、といったシナリオが考えられます。
フォームを提示するには、`reversi-game`ストリームに次のメッセージを送信します:
```javascript
{
type: 'init-form',
body: [フォームコントロールの配列]
}
```
フォームコントロールの配列については今から説明します。 フォームコントロールは、次のようなオブジェクトです:
```javascript
{
id: 'switch1',
type: 'switch',
label: 'Enable hoge',
value: false
}
```
`id` ... コントロールのID。 `type` ... コントロールの種類。後述します。 `label` ... コントロールと一緒に表記するテキスト。 `value` ... コントロールのデフォルト値。
### フォームの操作を受け取る
ユーザーがフォームを操作すると、ストリームから`update-form`イベントが流れてきます。 イベントの中身には、コントロールのIDと、ユーザーが設定した値が含まれています。 例えば、上で示したスイッチをユーザーがオンにしたとすると、次のイベントが流れてきます:
```javascript
{
id: 'switch1',
value: true
}
```
### フォームコントロールの種類
#### スイッチ
type: `switch` スイッチを表示します。何かの機能をオン/オフさせたい場合に有用です。
##### プロパティ
`label` ... スイッチに表記するテキスト。
#### ラジオボタン
type: `radio` ラジオボタンを表示します。選択肢を提示するのに有用です。例えば、Botの強さを設定させるなどです。
##### プロパティ
`items` ... ラジオボタンの選択肢。例:
```javascript
items: [{
label: '弱',
value: 1
}, {
label: '中',
value: 2
}, {
label: '強',
value: 3
}]
```
#### スライダー
type: `slider` スライダーを表示します。
##### プロパティ
`min` ... スライダーの下限。 `max` ... スライダーの上限。 `step` ... 入力欄で刻むステップ値。
#### テキストボックス
type: `textbox` テキストボックスを表示します。ユーザーになにか入力させる一般的な用途に利用できます。
## ユーザーにメッセージを表示する
設定画面でユーザーと対話する、フォーム以外のもうひとつの方法がこれです。ユーザーになにかメッセージを表示することができます。 例えば、ユーザーがBotの対応していないモードやマップを選択したとき、警告を表示するなどです。 メッセージを表示するには、次のメッセージをストリームに送信します:
```javascript
{
type: 'message',
body: {
text: 'メッセージ内容',
type: 'メッセージの種類'
}
}
```
メッセージの種類: `success`, `info`, `warning`, `error`
## 投了する
投了をするには、<a href="./api/endpoints/games/reversi/games/surrender">このエンドポイント</a>にリクエストします。

354
src/docs/ht-HT/stream.md Normal file
View File

@@ -0,0 +1,354 @@
# ストリーミングAPI
ストリーミングAPIを使うと、リアルタイムで様々な情報(例えばタイムラインに新しい投稿が流れてきた、メッセージが届いた、フォローされた、など)を受け取ったり、様々な操作を行ったりすることができます。
## ストリームに接続する
ストリーミングAPIを利用するには、まずMisskeyサーバーに**websocket**接続する必要があります。
以下のURLに、`i`というパラメータ名で認証情報を含めて、websocket接続してください。例:
```
%WS_URL%/streaming?i=xxxxxxxxxxxxxxx
```
認証情報は、自分のAPIキーや、アプリケーションからストリームに接続する際はユーザーのアクセストークンのことを指します。
<div class="ui info">
<p><i class="fas fa-info-circle"></i> 認証情報の取得については、<a href="./api">こちらのドキュメント</a>をご確認ください。</p>
</div>
---
認証情報は省略することもできますが、その場合非ログインでの利用ということになり、受信できる情報や可能な操作は限られます。例:
```
%WS_URL%/streaming
```
---
ストリームに接続すると、後述するAPI操作や、投稿の購読を行ったりすることができます。 しかしまだこの段階では、例えばタイムラインへの新しい投稿を受信したりすることはできません。 それを行うには、ストリーム上で、後述する**チャンネル**に接続する必要があります。
**ストリームでのやり取りはすべてJSONです。**
## チャンネル
MisskeyのストリーミングAPIにはチャンネルという概念があります。これは、送受信する情報を分離するための仕組みです。 Misskeyのストリームに接続しただけでは、まだリアルタイムでタイムラインの投稿を受信したりはできません。 ストリーム上でチャンネルに接続することで、様々な情報を受け取ったり情報を送信したりすることができるようになります。
### チャンネルに接続する
チャンネルに接続するには、次のようなデータをJSONでストリームに送信します:
```json
{
type: 'connect',
body: {
channel: 'xxxxxxxx',
id: 'foobar',
params: {
...
}
}
}
```
ここで、
* `channel`には接続したいチャンネル名を設定します。チャンネルの種類については後述します。
* `id`にはそのチャンネルとやり取りするための任意のIDを設定します。ストリームでは様々なメッセージが流れるので、そのメッセージがどのチャンネルからのものなのか識別する必要があるからです。このIDは、UUIDや、乱数のようなもので構いません。
* `params`はチャンネルに接続する際のパラメータです。チャンネルによって接続時に必要とされるパラメータは異なります。パラメータ不要のチャンネルに接続する際は、このプロパティは省略可能です。
<div class="ui info">
<p><i class="fas fa-info-circle"></i> IDはチャンネルごとではなく「チャンネルの接続ごと」です。なぜなら、同じチャンネルに異なるパラメータで複数接続するケースもあるからです。</p>
</div>
### チャンネルからのメッセージを受け取る
例えばタイムラインのチャンネルなら、新しい投稿があった時にメッセージを発します。そのメッセージを受け取ることで、タイムラインに新しい投稿がされたことをリアルタイムで知ることができます。
チャンネルがメッセージを発すると、次のようなデータがJSONでストリームに流れてきます:
```json
{
type: 'channel',
body: {
id: 'foobar',
type: 'something',
body: {
some: 'thing'
}
}
}
```
ここで、
* `id`には前述したそのチャンネルに接続する際に設定したIDが設定されています。これで、このメッセージがどのチャンネルからのものなのか知ることができます。
* `type`にはメッセージの種類が設定されます。チャンネルによって、どのような種類のメッセージが流れてくるかは異なります。
* `body`にはメッセージの内容が設定されます。チャンネルによって、どのような内容のメッセージが流れてくるかは異なります。
### チャンネルに向けてメッセージを送信する
チャンネルによっては、メッセージを受け取るだけでなく、こちらから何かメッセージを送信し、何らかの操作を行える場合があります。
チャンネルにメッセージを送信するには、次のようなデータをJSONでストリームに送信します:
```json
{
type: 'channel',
body: {
id: 'foobar',
type: 'something',
body: {
some: 'thing'
}
}
}
```
ここで、
* `id`には前述したそのチャンネルに接続する際に設定したIDを設定します。これで、このメッセージがどのチャンネルに向けたものなのか識別させることができます。
* `type`にはメッセージの種類を設定します。チャンネルによって、どのような種類のメッセージを受け付けるかは異なります。
* `body`にはメッセージの内容を設定します。チャンネルによって、どのような内容のメッセージを受け付けるかは異なります。
### チャンネルから切断する
チャンネルから切断するには、次のようなデータをJSONでストリームに送信します:
```json
{
type: 'disconnect',
body: {
id: 'foobar'
}
}
```
ここで、
* `id`には前述したそのチャンネルに接続する際に設定したIDを設定します。
## ストリームを経由してAPIリクエストする
ストリームを経由してAPIリクエストすると、HTTPリクエストを発生させずにAPIを利用できます。そのため、コードを簡潔にできたり、パフォーマンスの向上を見込めるかもしれません。
ストリームを経由してAPIリクエストするには、次のようなデータをJSONでストリームに送信します:
```json
{
type: 'api',
body: {
id: 'xxxxxxxxxxxxxxxx',
endpoint: 'notes/create',
data: {
text: 'yee haw!'
}
}
}
```
ここで、
* `id`には、APIのレスポンスを識別するための、APIリクエストごとの一意なIDを設定する必要があります。UUIDや、簡単な乱数のようなもので構いません。
* `endpoint`には、あなたがリクエストしたいAPIのエンドポイントを指定します。
* `data`には、エンドポイントのパラメータを含めます。
<div class="ui info">
<p><i class="fas fa-info-circle"></i> APIのエンドポイントやパラメータについてはAPIリファレンスをご確認ください。</p>
</div>
### レスポンスの受信
APIへリクエストすると、レスポンスがストリームから次のような形式で流れてきます。
```json
{
type: 'api:xxxxxxxxxxxxxxxx',
body: {
...
}
}
```
ここで、
* `xxxxxxxxxxxxxxxx`の部分には、リクエストの際に設定された`id`が含まれています。これにより、どのリクエストに対するレスポンスなのか判別することができます。
* `body`には、レスポンスが含まれています。
## 投稿のキャプチャ
Misskeyは投稿のキャプチャと呼ばれる仕組みを提供しています。これは、指定した投稿のイベントをストリームで受け取る機能です。
例えばタイムラインを取得してユーザーに表示したとします。ここで誰かがそのタイムラインに含まれるどれかの投稿に対してリアクションしたとします。
しかし、クライアントからするとある投稿にリアクションが付いたことなどは知る由がないため、リアルタイムでリアクションをタイムライン上の投稿に反映して表示するといったことができません。
この問題を解決するために、Misskeyは投稿のキャプチャ機構を用意しています。投稿をキャプチャすると、その投稿に関するイベントを受け取ることができるため、リアルタイムでリアクションを反映させたりすることが可能になります。
### 投稿をキャプチャする
投稿をキャプチャするには、ストリームに次のようなメッセージを送信します:
```json
{
type: 'subNote',
body: {
id: 'xxxxxxxxxxxxxxxx'
}
}
```
ここで、
* `id`にキャプチャしたい投稿の`id`を設定します。
このメッセージを送信すると、Misskeyにキャプチャを要請したことになり、以後、その投稿に関するイベントが流れてくるようになります。
例えば投稿にリアクションが付いたとすると、次のようなメッセージが流れてきます:
```json
{
type: 'noteUpdated',
body: {
id: 'xxxxxxxxxxxxxxxx',
type: 'reacted',
body: {
reaction: 'like',
userId: 'yyyyyyyyyyyyyyyy'
}
}
}
```
ここで、
* `body`内の`id`に、イベントを発生させた投稿のIDが設定されます。
* `body`内の`type`に、イベントの種類が設定されます。
* `body`内の`body`に、イベントの詳細が設定されます。
#### イベントの種類
##### `reacted`
その投稿にリアクションがされた時に発生します。
* `reaction`に、リアクションの種類が設定されます。
* `userId`に、リアクションを行ったユーザーのIDが設定されます。
例:
```json
{
type: 'noteUpdated',
body: {
id: 'xxxxxxxxxxxxxxxx',
type: 'reacted',
body: {
reaction: 'like',
userId: 'yyyyyyyyyyyyyyyy'
}
}
}
```
##### `deleted`
その投稿が削除された時に発生します。
* `deletedAt`に、削除日時が設定されます。
例:
```json
{
type: 'noteUpdated',
body: {
id: 'xxxxxxxxxxxxxxxx',
type: 'deleted',
body: {
deletedAt: '2018-10-22T02:17:09.703Z'
}
}
}
```
##### `pollVoted`
その投稿に添付されたアンケートに投票された時に発生します。
* `choice`に、選択肢IDが設定されます。
* `userId`に、投票を行ったユーザーのIDが設定されます。
例:
```json
{
type: 'noteUpdated',
body: {
id: 'xxxxxxxxxxxxxxxx',
type: 'pollVoted',
body: {
choice: 2,
userId: 'yyyyyyyyyyyyyyyy'
}
}
}
```
### 投稿のキャプチャを解除する
その投稿がもう画面に表示されなくなったりして、その投稿に関するイベントをもう受け取る必要がなくなったときは、キャプチャの解除を申請してください。
次のメッセージを送信します:
```json
{
type: 'unsubNote',
body: {
id: 'xxxxxxxxxxxxxxxx'
}
}
```
ここで、
* `id`にキャプチャを解除したい投稿の`id`を設定します。
このメッセージを送信すると、以後、その投稿に関するイベントは流れてこないようになります。
# チャンネル一覧
## `main`
アカウントに関する基本的な情報が流れてきます。このチャンネルにパラメータはありません。
### 流れてくるイベント一覧
#### `renote`
自分の投稿がRenoteされた時に発生するイベントです。自分自身の投稿をRenoteしたときは発生しません。
#### `mention`
誰かからメンションされたときに発生するイベントです。
#### `readAllNotifications`
自分宛ての通知がすべて既読になったことを表すイベントです。このイベントを利用して、「通知があることを示すアイコン」のようなものをオフにしたりする等のケースが想定されます。
#### `meUpdated`
自分の情報が更新されたことを表すイベントです。
#### `follow`
自分が誰かをフォローしたときに発生するイベントです。
#### `unfollow`
自分が誰かのフォローを解除したときに発生するイベントです。
#### `followed`
自分が誰かにフォローされたときに発生するイベントです。
## `homeTimeline`
ホームタイムラインの投稿情報が流れてきます。このチャンネルにパラメータはありません。
### 流れてくるイベント一覧
#### `note`
タイムラインに新しい投稿が流れてきたときに発生するイベントです。
## `localTimeline`
ローカルタイムラインの投稿情報が流れてきます。このチャンネルにパラメータはありません。
### 流れてくるイベント一覧
#### `note`
ローカルタイムラインに新しい投稿が流れてきたときに発生するイベントです。
## `hybridTimeline`
ソーシャルタイムラインの投稿情報が流れてきます。このチャンネルにパラメータはありません。
### 流れてくるイベント一覧
#### `note`
ソーシャルタイムラインに新しい投稿が流れてきたときに発生するイベントです。
## `globalTimeline`
グローバルタイムラインの投稿情報が流れてきます。このチャンネルにパラメータはありません。
### 流れてくるイベント一覧
#### `note`
グローバルタイムラインに新しい投稿が流れてきたときに発生するイベントです。

68
src/docs/ht-HT/theme.md Normal file
View File

@@ -0,0 +1,68 @@
# テーマ
テーマを設定して、Misskeyクライアントの見た目を変更できます。
## テーマの設定
設定 > テーマ
## テーマを作成する
テーマコードはJSON5で記述されたテーマオブジェクトです。 テーマは以下のようなオブジェクトです。
``` js
{
id: '17587283-dd92-4a2c-a22c-be0637c9e22a',
name: 'Danboard',
author: 'syuilo',
base: 'light',
props: {
accent: 'rgb(218, 141, 49)',
bg: 'rgb(218, 212, 190)',
fg: 'rgb(115, 108, 92)',
panel: 'rgb(236, 232, 220)',
renote: 'rgb(100, 152, 106)',
link: 'rgb(100, 152, 106)',
mention: '@accent',
hashtag: 'rgb(100, 152, 106)',
header: 'rgba(239, 227, 213, 0.75)',
navBg: 'rgb(216, 206, 182)',
inputBorder: 'rgba(0, 0, 0, 0.1)',
},
}
```
* `id` ... テーマの一意なID。UUIDをおすすめします。
* `name` ... テーマ名
* `author` ... テーマの作者
* `desc` ... テーマの説明(オプション)
* `base` ... 明るいテーマか、暗いテーマか
* `light`にすると明るいテーマになり、`dark`にすると暗いテーマになります。
* テーマはここで設定されたベーステーマを継承します。
* `props` ... テーマのスタイル定義。これから説明します。
### テーマのスタイル定義
`props`下にはテーマのスタイルを定義します。 キーがCSSの変数名になり、バリューで中身を指定します。 なお、この`props`オブジェクトはベーステーマから継承されます。 ベーステーマは、このテーマの`base`が`light`なら[_light.json5](https://github.com/syuilo/misskey/blob/develop/src/client/themes/_light.json5)で、`dark`なら[_dark.json5](https://github.com/syuilo/misskey/blob/develop/src/client/themes/_dark.json5)です。 つまり、このテーマ内の`props`に`panel`というキーが無くても、そこにはベーステーマの`panel`があると見なされます。
#### バリューで使える構文
* 16進数で表された色
* 例: `#00ff00`
* `rgb(r, g, b)`形式で表された色
* 例: `rgb(0, 255, 0)`
* `rgb(r, g, b, a)`形式で表された透明度を含む色
* 例: `rgba(0, 255, 0, 0.5)`
* 他のキーの値の参照
* `@{キー名}`と書くと他のキーの値の参照になります。`{キー名}`は参照したいキーの名前に置き換えます。
* 例: `@panel`
* 定数(後述)の参照
* `${定数名}`と書くと定数の参照になります。`{定数名}`は参照したい定数の名前に置き換えます。
* 例: `$main`
* 関数(後述)
* `:{関数名}<{引数}<{色}`
#### 定数
「CSS変数として出力はしたくないが、他のCSS変数の値として使いまわしたい」値があるときは、定数を使うと便利です。 キー名を`$`で始めると、そのキーはCSS変数として出力されません。
#### 関数
wip

View File

@@ -0,0 +1,15 @@
# タイムラインの比較
https://docs.google.com/spreadsheets/d/1lxQ2ugKrhz58Bg96HTDK_2F98BUritkMyIiBkOByjHA/edit?usp=sharing
## ホーム
自分のフォローしているユーザーの投稿
## ローカル
全てのローカルユーザーの「ホーム」指定されていない投稿
## ソーシャル
自分のフォローしているユーザーの投稿と、全てのローカルユーザーの「ホーム」指定されていない投稿
## グローバル
全てのローカルユーザーの「ホーム」指定されていない投稿と、サーバーに届いた全てのリモートユーザーの「ホーム」指定されていない投稿

View File

@@ -0,0 +1,4 @@
# AiScript
## 関数
デフォルトで値渡しです。

58
src/docs/it-IT/api.md Normal file
View File

@@ -0,0 +1,58 @@
# Misskey API
MisskeyAPIを使ってMisskeyクライアント、Misskey連携Webサービス、Bot等(以下「アプリケーション」と呼びます)を開発できます。 ストリーミングAPIもあるので、リアルタイム性のあるアプリケーションを作ることも可能です。
APIを使い始めるには、まずアクセストークンを取得する必要があります。 このドキュメントでは、アクセストークンを取得する手順を説明した後、基本的なAPIの使い方を説明します。
## アクセストークンの取得
基本的に、APIはリクエストにはアクセストークンが必要となります。 APIにリクエストするのが自分自身なのか、不特定の利用者に使ってもらうアプリケーションなのかによって取得手順は異なります。
* 前者の場合: [「自分自身のアクセストークンを手動発行する」](#自分自身のアクセストークンを手動発行する)に進む
* 後者の場合: [「アプリケーション利用者にアクセストークンの発行をリクエストする」](#アプリケーション利用者にアクセストークンの発行をリクエストする)に進む
### 自分自身のアクセストークンを手動発行する
「設定 > API」で、自分のアクセストークンを発行できます。
[「APIの使い方」へ進む](#APIの使い方)
### アプリケーション利用者にアクセストークンの発行をリクエストする
アプリケーション利用者のアクセストークンを取得するには、以下の手順で発行をリクエストします。
#### Step 1
UUIDを生成する。以後これをセッションIDと呼びます。
> このセッションIDは毎回生成し、使いまわさないようにしてください。
#### Step 2
`{_URL_}/miauth/{session}`をユーザーのブラウザで表示させる。`{session}`の部分は、セッションIDに置き換えてください。
> 例: `{_URL_}/miauth/c1f6d42b-468b-4fd2-8274-e58abdedef6f`
表示する際、URLにクエリパラメータとしていくつかのオプションを設定できます:
* `name` ... アプリケーション名
* > 例: `MissDeck`
* `icon` ... アプリケーションのアイコン画像URL
* > 例: `https://missdeck.example.com/icon.png`
* `callback` ... 認証が終わった後にリダイレクトするURL
* > 例: `https://missdeck.example.com/callback`
* リダイレクト時には、`session`というクエリパラメータでセッションIDが付きます
* `permission` ... アプリケーションが要求する権限
* > 例: `write:notes,write:following,read:drive`
* 要求する権限を`,`で区切って列挙します
* どのような権限があるかは[APIリファレンス](/api-doc)で確認できます
#### Step 3
ユーザーが発行を許可した後、`{_URL_}/api/miauth/{session}/check`にPOSTリクエストすると、レスポンスとしてアクセストークンを含むJSONが返ります。
レスポンスに含まれるプロパティ:
* `token` ... ユーザーのアクセストークン
* `user` ... ユーザーの情報
[「APIの使い方」へ進む](#APIの使い方)
## APIの使い方
**APIはすべてPOSTで、リクエスト/レスポンスともにJSON形式です。RESTではありません。** アクセストークンは、`i`というパラメータ名でリクエストに含めます。
* [APIリファレンス](/api-doc)
* [ストリーミングAPI](./stream)

View File

@@ -0,0 +1,74 @@
# プラグインの作成
Misskey Webクライアントのプラグイン機能を使うと、クライアントを拡張し、様々な機能を追加できます。 ここではプラグインの作成にあたってのメタデータ定義や、AiScript APIリファレンスを掲載します。
## メタデータ
プラグインは、AiScriptのメタデータ埋め込み機能を使って、デフォルトとしてプラグインのメタデータを定義する必要があります。 メタデータは次のプロパティを含むオブジェクトです。
### name
プラグイン名
### author
プラグイン作者
### version
プラグインバージョン。数値を指定してください。
### description
プラグインの説明
### permissions
プラグインが要求する権限。MisskeyAPIにリクエストする際に用いられます。
### config
プラグインの設定情報を表すオブジェクト。 キーに設定名、値に以下のプロパティを含めます。
#### type
設定値の種類を表す文字列。以下から選択します。 string number boolean
#### label
ユーザーに表示する設定名
#### description
設定の説明
#### default
設定のデフォルト値
## APIリファレンス
AiScript標準で組み込まれているAPIは掲載しません。
### Mk:dialog(title text type)
ダイアログを表示します。typeには以下の値が設定できます。 info success warn error question 省略すると info になります。
### Mk:confirm(title text type)
確認ダイアログを表示します。typeには以下の値が設定できます。 info success warn error question 省略すると question になります。 ユーザーが"OK"を選択した場合は true を、"キャンセル"を選択した場合は false が返ります。
### Mk:api(endpoint params)
Misskey APIにリクエストします。第一引数にエンドポイント名、第二引数にパラメータオブジェクトを渡します。
### Mk:save(key value)
任意の値に任意の名前を付けて永続化します。永続化した値は、AiScriptコンテキストが終了しても残り、Mk:loadで読み取ることができます。
### Mk:load(key)
Mk:saveで永続化した指定の名前の値を読み取ります。
### Plugin:register_post_form_action(title fn)
投稿フォームにアクションを追加します。第一引数にアクション名、第二引数にアクションが選択された際のコールバック関数を渡します。 コールバック関数には、第一引数に投稿フォームオブジェクトが渡されます。
### Plugin:register_note_action(title fn)
ノートメニューに項目を追加します。第一引数に項目名、第二引数に項目が選択された際のコールバック関数を渡します。 コールバック関数には、第一引数に対象のノートオブジェクトが渡されます。
### Plugin:register_user_action(title fn)
ユーザーメニューに項目を追加します。第一引数に項目名、第二引数に項目が選択された際のコールバック関数を渡します。 コールバック関数には、第一引数に対象のユーザーオブジェクトが渡されます。
### Plugin:register_note_view_interruptor(fn)
UIに表示されるート情報を書き換えます。 コールバック関数には、第一引数に対象のノートオブジェクトが渡されます。 コールバック関数の返り値でノートが書き換えられます。
### Plugin:register_note_post_interruptor(fn)
ノート投稿時にノート情報を書き換えます。 コールバック関数には、第一引数に対象のノートオブジェクトが渡されます。 コールバック関数の返り値でノートが書き換えられます。
### Plugin:open_url(url)
第一引数に渡されたURLをブラウザの新しいタブで開きます。
### Plugin:config
プラグインの設定が格納されるオブジェクト。プラグイン定義のconfigで設定したキーで値が入ります。

View File

@@ -0,0 +1,2 @@
# カスタム絵文字
カスタム絵文字は、インスタンスで用意された画像を絵文字のように使える機能です。 ノート、リアクション、チャット、自己紹介、名前などの場所で使うことができます。 カスタム絵文字をそれらの場所で使うには、絵文字ピッカーボタン(ある場合)を押すか、`:`を入力して絵文字サジェストを表示します。 テキスト内に`:foo:`のような形式の文字列が見つかると、`foo`の部分がカスタム絵文字名と解釈され、表示時には対応したカスタム絵文字に置き換わります。

18
src/docs/it-IT/deck.md Normal file
View File

@@ -0,0 +1,18 @@
# デッキ
デッキは利用可能なUIのひとつです。「カラム」と呼ばれるビューを複数並べて表示させることで、カスタマイズ性が高く、情報量の多いUIが構築できることが特徴です。
## カラムの追加
デッキの背景を右クリックし、「カラムを追加」して任意のカラムを追加できます。
## カラムの移動
カラムは、ドラッグアンドドロップで他のカラムと位置を入れ替えることが出来るほか、カラムメニュー(カラムのヘッダー右クリック)から位置を移動させることもできます。
## カラムの水平分割
カラムは左右だけでなく、上下に並べることもできます。 カラムメニューを開き、「左に重ねる」を選択すると、左のカラムの下に現在のカラムが移動します。 上下分割を解除するには、カラムメニューの「右に出す」を選択します。
## カラムの設定
カラムメニューの「編集」を選択するとカラムの設定を編集できます。カラムの名前を変えたり、幅を変えたりできます。
## デッキの設定
デッキに関する設定は、[settings/deck](/settings/deck)で行えます。

2
src/docs/it-IT/follow.md Normal file
View File

@@ -0,0 +1,2 @@
# フォロー
ユーザーをフォローすると、タイムラインにそのユーザーの投稿が表示されるようになります。ただし、他のユーザーに対する返信は含まれません。 ユーザーをフォローするには、ユーザーページの「フォロー」ボタンをクリックします。フォローを解除するには、もう一度クリックします。

View File

@@ -0,0 +1,68 @@
# キーボードショートカット
## グローバル
これらのショートカットは基本的にどこでも使えます。
<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">S</kbd></td><td>検索</td><td><b>S</b>earch</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">R</kbd></td><td>返信フォームを開く</td><td><b>R</b>eply</td></tr>
<tr><td><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">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">F</kbd>, <kbd class="key">B</kbd></td><td>お気に入りに登録</td><td><b>F</b>avorite, <b>B</b>ookmark</td></tr>
<tr><td><kbd class="key">Del</kbd>, <kbd class="group"><kbd class="key">Ctrl</kbd> + <kbd class="key">D</kbd></kbd></td><td>投稿を削除</td><td><b>D</b>elete</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>

2
src/docs/it-IT/mfm.md Normal file
View File

@@ -0,0 +1,2 @@
# MFM
MFMは、Misskey Flavored Markdownの略で、Misskeyの様々な場所で使用できる専用のマークアップ言語です。 MFMで使用可能な構文は[MFMチートシート](/mfm-cheat-sheet)で確認できます。

13
src/docs/it-IT/mute.md Normal file
View File

@@ -0,0 +1,13 @@
# ミュート
ユーザーをミュートすると、そのユーザーに関する次のコンテンツがMisskeyに表示されなくなります:
* タイムラインや投稿の検索結果内の、そのユーザーの投稿(およびそれらの投稿に対する返信やRenote)
* そのユーザーからの通知
* メッセージ履歴一覧内の、そのユーザーとのメッセージ履歴
ユーザーをミュートするには、対象のユーザーのユーザーページに表示されている「ミュート」ボタンを押します。
ミュートを行ったことは相手に通知されず、ミュートされていることを知ることもできません。
設定>ミュート から、自分がミュートしているユーザー一覧を確認することができます。

10
src/docs/it-IT/pages.md Normal file
View File

@@ -0,0 +1,10 @@
# Pages
## 変数
変数を使うことで動的なページを作成できます。テキスト内で <b>{ 変数名 }</b> と書くとそこに変数の値を埋め込めます。例えば <b>Hello { thing } world!</b> というテキストで、変数(thing)の値が <b>ai</b> だった場合、テキストは <b>Hello ai world!</b> になります。
変数の評価(値を算出すること)は上から下に行われるので、ある変数の中で自分より下の変数を参照することはできません。例えば上から <b>A、B、C</b> と3つの変数を定義したとき、<b>C</b>の中で<b>A</b><b>B</b>を参照することはできますが、<b>A</b>の中で<b>B</b><b>C</b>を参照することはできません。
ユーザーからの入力を受け取るには、ページに「ユーザー入力」ブロックを設置し、「変数名」に入力を格納したい変数名を設定します(変数は自動で作成されます)。その変数を使ってユーザー入力に応じた動作を行えます。
関数を使うと、値の算出処理を再利用可能な形にまとめることができます。関数を作るには、「関数」タイプの変数を作成します。関数にはスロット(引数)を設定することができ、スロットの値は関数内で変数として利用可能です。また、関数を引数に取る関数(高階関数と呼ばれます)も存在します。関数は予め定義しておくほかに、このような高階関数のスロットに即席でセットすることもできます。

View File

@@ -0,0 +1,11 @@
# リアクション
他の人のノートに、絵文字を付けて簡単にあなたの反応を伝えられる機能です。 リアクションするには、ノートの + アイコンをクリックしてピッカーを表示し、絵文字を選択します。 リアクションには[カスタム絵文字](./custom-emoji)も使用できます。
## リアクションピッカーのカスタマイズ
ピッカーに表示される絵文字を自分好みにカスタマイズすることができます。 設定の「リアクション」で設定します。
## リモート投稿へのリアクションについて
リアクションはMisskeyオリジナルの機能であるため、リモートインスタンスがMisskeyでない限りは、ほとんどの場合「Like」としてアクティビティが送信されます。一般的にはLikeは「お気に入り」として実装されているようです。 また、相手がMisskeyであったとしても、カスタム絵文字リアクションは伝わらず、自動的に「👍」等にフォールバックされます。
## リモートからのリアクションについて
リモートから「Like」アクティビティを受信したとき、Misskeyでは「👍」のリアクションとして解釈されます。

View File

@@ -0,0 +1,160 @@
# MisskeyリバーシBotの開発
Misskeyのリバーシ機能に対応したBotの開発方法をここに記します。
1. `games/reversi`ストリームに以下のパラメータを付けて接続する:
* `i`: botアカウントのAPIキー
2. 対局への招待が来たら、ストリームから`invited`イベントが流れてくる
* イベントの中身に、`parent`という名前で対局へ誘ってきたユーザーの情報が含まれている
3. `games/reversi/match`へ、`user_id`として`parent``id`が含まれたリクエストを送信する
4. 上手くいくとゲーム情報が返ってくるので、`games/reversi-game`ストリームへ、以下のパラメータを付けて接続する:
* `i`: botアカウントのAPIキー
* `game`: `game``id`
5. この間、相手がゲームの設定を変更するとその都度`update-settings`イベントが流れてくるので、必要であれば何かしらの処理を行う
6. 設定に満足したら、`{ type: 'accept' }`メッセージをストリームに送信する
7. ゲームが開始すると、`started`イベントが流れてくる
* イベントの中身にはゲーム情報が含まれている
8. 石を打つには、ストリームに`{ type: 'set', pos: <位置> }`を送信する(位置の計算方法は後述)
9. 相手または自分が石を打つと、ストリームから`set`イベントが流れてくる
* `color`として石の色が含まれている
* `pos`として位置情報が含まれている
## 位置の計算法
8x8のマップを考える場合、各マスの位置(インデックスと呼びます)は次のようになっています:
```
+--+--+--+--+--+--+--+--+
| 0| 1| 2| 3| 4| 5| 6| 7|
+--+--+--+--+--+--+--+--+
| 8| 9|10|11|12|13|14|15|
+--+--+--+--+--+--+--+--+
|16|17|18|19|20|21|22|23|
...
```
### X,Y座標 から インデックス に変換する
```
pos = x + (y * mapWidth)
```
`mapWidth`は、ゲーム情報の`map`から、次のようにして計算できます:
```
mapWidth = map[0].length
```
### インデックス から X,Y座標 に変換する
```
x = pos % mapWidth
y = Math.floor(pos / mapWidth)
```
## マップ情報
マップ情報は、ゲーム情報の`map`に入っています。 文字列の配列になっており、ひとつひとつの文字がマス情報を表しています。 それをもとにマップのデザインを知る事が出来ます:
* `(スペース)` ... マス無し
* `-` ... マス
* `b` ... 初期配置される黒石
* `w` ... 初期配置される白石
例えば、4*4の次のような単純なマップがあるとします:
```text
+---+---+---+---+
| | | | |
+---+---+---+---+
| | ○ | ● | |
+---+---+---+---+
| | ● | ○ | |
+---+---+---+---+
| | | | |
+---+---+---+---+
```
この場合、マップデータはこのようになります:
```javascript
['----', '-wb-', '-bw-', '----']
```
## ユーザーにフォームを提示して対話可能Botを作成する
ユーザーとのコミュニケーションを行うため、ゲームの設定画面でユーザーにフォームを提示することができます。 例えば、Botの強さをユーザーが設定できるようにする、といったシナリオが考えられます。
フォームを提示するには、`reversi-game`ストリームに次のメッセージを送信します:
```javascript
{
type: 'init-form',
body: [フォームコントロールの配列]
}
```
フォームコントロールの配列については今から説明します。 フォームコントロールは、次のようなオブジェクトです:
```javascript
{
id: 'switch1',
type: 'switch',
label: 'Enable hoge',
value: false
}
```
`id` ... コントロールのID。 `type` ... コントロールの種類。後述します。 `label` ... コントロールと一緒に表記するテキスト。 `value` ... コントロールのデフォルト値。
### フォームの操作を受け取る
ユーザーがフォームを操作すると、ストリームから`update-form`イベントが流れてきます。 イベントの中身には、コントロールのIDと、ユーザーが設定した値が含まれています。 例えば、上で示したスイッチをユーザーがオンにしたとすると、次のイベントが流れてきます:
```javascript
{
id: 'switch1',
value: true
}
```
### フォームコントロールの種類
#### スイッチ
type: `switch` スイッチを表示します。何かの機能をオン/オフさせたい場合に有用です。
##### プロパティ
`label` ... スイッチに表記するテキスト。
#### ラジオボタン
type: `radio` ラジオボタンを表示します。選択肢を提示するのに有用です。例えば、Botの強さを設定させるなどです。
##### プロパティ
`items` ... ラジオボタンの選択肢。例:
```javascript
items: [{
label: '弱',
value: 1
}, {
label: '中',
value: 2
}, {
label: '強',
value: 3
}]
```
#### スライダー
type: `slider` スライダーを表示します。
##### プロパティ
`min` ... スライダーの下限。 `max` ... スライダーの上限。 `step` ... 入力欄で刻むステップ値。
#### テキストボックス
type: `textbox` テキストボックスを表示します。ユーザーになにか入力させる一般的な用途に利用できます。
## ユーザーにメッセージを表示する
設定画面でユーザーと対話する、フォーム以外のもうひとつの方法がこれです。ユーザーになにかメッセージを表示することができます。 例えば、ユーザーがBotの対応していないモードやマップを選択したとき、警告を表示するなどです。 メッセージを表示するには、次のメッセージをストリームに送信します:
```javascript
{
type: 'message',
body: {
text: 'メッセージ内容',
type: 'メッセージの種類'
}
}
```
メッセージの種類: `success`, `info`, `warning`, `error`
## 投了する
投了をするには、<a href="./api/endpoints/games/reversi/games/surrender">このエンドポイント</a>にリクエストします。

354
src/docs/it-IT/stream.md Normal file
View File

@@ -0,0 +1,354 @@
# ストリーミングAPI
ストリーミングAPIを使うと、リアルタイムで様々な情報(例えばタイムラインに新しい投稿が流れてきた、メッセージが届いた、フォローされた、など)を受け取ったり、様々な操作を行ったりすることができます。
## ストリームに接続する
ストリーミングAPIを利用するには、まずMisskeyサーバーに**websocket**接続する必要があります。
以下のURLに、`i`というパラメータ名で認証情報を含めて、websocket接続してください。例:
```
%WS_URL%/streaming?i=xxxxxxxxxxxxxxx
```
認証情報は、自分のAPIキーや、アプリケーションからストリームに接続する際はユーザーのアクセストークンのことを指します。
<div class="ui info">
<p><i class="fas fa-info-circle"></i> 認証情報の取得については、<a href="./api">こちらのドキュメント</a>をご確認ください。</p>
</div>
---
認証情報は省略することもできますが、その場合非ログインでの利用ということになり、受信できる情報や可能な操作は限られます。例:
```
%WS_URL%/streaming
```
---
ストリームに接続すると、後述するAPI操作や、投稿の購読を行ったりすることができます。 しかしまだこの段階では、例えばタイムラインへの新しい投稿を受信したりすることはできません。 それを行うには、ストリーム上で、後述する**チャンネル**に接続する必要があります。
**ストリームでのやり取りはすべてJSONです。**
## チャンネル
MisskeyのストリーミングAPIにはチャンネルという概念があります。これは、送受信する情報を分離するための仕組みです。 Misskeyのストリームに接続しただけでは、まだリアルタイムでタイムラインの投稿を受信したりはできません。 ストリーム上でチャンネルに接続することで、様々な情報を受け取ったり情報を送信したりすることができるようになります。
### チャンネルに接続する
チャンネルに接続するには、次のようなデータをJSONでストリームに送信します:
```json
{
type: 'connect',
body: {
channel: 'xxxxxxxx',
id: 'foobar',
params: {
...
}
}
}
```
ここで、
* `channel`には接続したいチャンネル名を設定します。チャンネルの種類については後述します。
* `id`にはそのチャンネルとやり取りするための任意のIDを設定します。ストリームでは様々なメッセージが流れるので、そのメッセージがどのチャンネルからのものなのか識別する必要があるからです。このIDは、UUIDや、乱数のようなもので構いません。
* `params`はチャンネルに接続する際のパラメータです。チャンネルによって接続時に必要とされるパラメータは異なります。パラメータ不要のチャンネルに接続する際は、このプロパティは省略可能です。
<div class="ui info">
<p><i class="fas fa-info-circle"></i> IDはチャンネルごとではなく「チャンネルの接続ごと」です。なぜなら、同じチャンネルに異なるパラメータで複数接続するケースもあるからです。</p>
</div>
### チャンネルからのメッセージを受け取る
例えばタイムラインのチャンネルなら、新しい投稿があった時にメッセージを発します。そのメッセージを受け取ることで、タイムラインに新しい投稿がされたことをリアルタイムで知ることができます。
チャンネルがメッセージを発すると、次のようなデータがJSONでストリームに流れてきます:
```json
{
type: 'channel',
body: {
id: 'foobar',
type: 'something',
body: {
some: 'thing'
}
}
}
```
ここで、
* `id`には前述したそのチャンネルに接続する際に設定したIDが設定されています。これで、このメッセージがどのチャンネルからのものなのか知ることができます。
* `type`にはメッセージの種類が設定されます。チャンネルによって、どのような種類のメッセージが流れてくるかは異なります。
* `body`にはメッセージの内容が設定されます。チャンネルによって、どのような内容のメッセージが流れてくるかは異なります。
### チャンネルに向けてメッセージを送信する
チャンネルによっては、メッセージを受け取るだけでなく、こちらから何かメッセージを送信し、何らかの操作を行える場合があります。
チャンネルにメッセージを送信するには、次のようなデータをJSONでストリームに送信します:
```json
{
type: 'channel',
body: {
id: 'foobar',
type: 'something',
body: {
some: 'thing'
}
}
}
```
ここで、
* `id`には前述したそのチャンネルに接続する際に設定したIDを設定します。これで、このメッセージがどのチャンネルに向けたものなのか識別させることができます。
* `type`にはメッセージの種類を設定します。チャンネルによって、どのような種類のメッセージを受け付けるかは異なります。
* `body`にはメッセージの内容を設定します。チャンネルによって、どのような内容のメッセージを受け付けるかは異なります。
### チャンネルから切断する
チャンネルから切断するには、次のようなデータをJSONでストリームに送信します:
```json
{
type: 'disconnect',
body: {
id: 'foobar'
}
}
```
ここで、
* `id`には前述したそのチャンネルに接続する際に設定したIDを設定します。
## ストリームを経由してAPIリクエストする
ストリームを経由してAPIリクエストすると、HTTPリクエストを発生させずにAPIを利用できます。そのため、コードを簡潔にできたり、パフォーマンスの向上を見込めるかもしれません。
ストリームを経由してAPIリクエストするには、次のようなデータをJSONでストリームに送信します:
```json
{
type: 'api',
body: {
id: 'xxxxxxxxxxxxxxxx',
endpoint: 'notes/create',
data: {
text: 'yee haw!'
}
}
}
```
ここで、
* `id`には、APIのレスポンスを識別するための、APIリクエストごとの一意なIDを設定する必要があります。UUIDや、簡単な乱数のようなもので構いません。
* `endpoint`には、あなたがリクエストしたいAPIのエンドポイントを指定します。
* `data`には、エンドポイントのパラメータを含めます。
<div class="ui info">
<p><i class="fas fa-info-circle"></i> APIのエンドポイントやパラメータについてはAPIリファレンスをご確認ください。</p>
</div>
### レスポンスの受信
APIへリクエストすると、レスポンスがストリームから次のような形式で流れてきます。
```json
{
type: 'api:xxxxxxxxxxxxxxxx',
body: {
...
}
}
```
ここで、
* `xxxxxxxxxxxxxxxx`の部分には、リクエストの際に設定された`id`が含まれています。これにより、どのリクエストに対するレスポンスなのか判別することができます。
* `body`には、レスポンスが含まれています。
## 投稿のキャプチャ
Misskeyは投稿のキャプチャと呼ばれる仕組みを提供しています。これは、指定した投稿のイベントをストリームで受け取る機能です。
例えばタイムラインを取得してユーザーに表示したとします。ここで誰かがそのタイムラインに含まれるどれかの投稿に対してリアクションしたとします。
しかし、クライアントからするとある投稿にリアクションが付いたことなどは知る由がないため、リアルタイムでリアクションをタイムライン上の投稿に反映して表示するといったことができません。
この問題を解決するために、Misskeyは投稿のキャプチャ機構を用意しています。投稿をキャプチャすると、その投稿に関するイベントを受け取ることができるため、リアルタイムでリアクションを反映させたりすることが可能になります。
### 投稿をキャプチャする
投稿をキャプチャするには、ストリームに次のようなメッセージを送信します:
```json
{
type: 'subNote',
body: {
id: 'xxxxxxxxxxxxxxxx'
}
}
```
ここで、
* `id`にキャプチャしたい投稿の`id`を設定します。
このメッセージを送信すると、Misskeyにキャプチャを要請したことになり、以後、その投稿に関するイベントが流れてくるようになります。
例えば投稿にリアクションが付いたとすると、次のようなメッセージが流れてきます:
```json
{
type: 'noteUpdated',
body: {
id: 'xxxxxxxxxxxxxxxx',
type: 'reacted',
body: {
reaction: 'like',
userId: 'yyyyyyyyyyyyyyyy'
}
}
}
```
ここで、
* `body`内の`id`に、イベントを発生させた投稿のIDが設定されます。
* `body`内の`type`に、イベントの種類が設定されます。
* `body`内の`body`に、イベントの詳細が設定されます。
#### イベントの種類
##### `reacted`
その投稿にリアクションがされた時に発生します。
* `reaction`に、リアクションの種類が設定されます。
* `userId`に、リアクションを行ったユーザーのIDが設定されます。
例:
```json
{
type: 'noteUpdated',
body: {
id: 'xxxxxxxxxxxxxxxx',
type: 'reacted',
body: {
reaction: 'like',
userId: 'yyyyyyyyyyyyyyyy'
}
}
}
```
##### `deleted`
その投稿が削除された時に発生します。
* `deletedAt`に、削除日時が設定されます。
例:
```json
{
type: 'noteUpdated',
body: {
id: 'xxxxxxxxxxxxxxxx',
type: 'deleted',
body: {
deletedAt: '2018-10-22T02:17:09.703Z'
}
}
}
```
##### `pollVoted`
その投稿に添付されたアンケートに投票された時に発生します。
* `choice`に、選択肢IDが設定されます。
* `userId`に、投票を行ったユーザーのIDが設定されます。
例:
```json
{
type: 'noteUpdated',
body: {
id: 'xxxxxxxxxxxxxxxx',
type: 'pollVoted',
body: {
choice: 2,
userId: 'yyyyyyyyyyyyyyyy'
}
}
}
```
### 投稿のキャプチャを解除する
その投稿がもう画面に表示されなくなったりして、その投稿に関するイベントをもう受け取る必要がなくなったときは、キャプチャの解除を申請してください。
次のメッセージを送信します:
```json
{
type: 'unsubNote',
body: {
id: 'xxxxxxxxxxxxxxxx'
}
}
```
ここで、
* `id`にキャプチャを解除したい投稿の`id`を設定します。
このメッセージを送信すると、以後、その投稿に関するイベントは流れてこないようになります。
# チャンネル一覧
## `main`
アカウントに関する基本的な情報が流れてきます。このチャンネルにパラメータはありません。
### 流れてくるイベント一覧
#### `renote`
自分の投稿がRenoteされた時に発生するイベントです。自分自身の投稿をRenoteしたときは発生しません。
#### `mention`
誰かからメンションされたときに発生するイベントです。
#### `readAllNotifications`
自分宛ての通知がすべて既読になったことを表すイベントです。このイベントを利用して、「通知があることを示すアイコン」のようなものをオフにしたりする等のケースが想定されます。
#### `meUpdated`
自分の情報が更新されたことを表すイベントです。
#### `follow`
自分が誰かをフォローしたときに発生するイベントです。
#### `unfollow`
自分が誰かのフォローを解除したときに発生するイベントです。
#### `followed`
自分が誰かにフォローされたときに発生するイベントです。
## `homeTimeline`
ホームタイムラインの投稿情報が流れてきます。このチャンネルにパラメータはありません。
### 流れてくるイベント一覧
#### `note`
タイムラインに新しい投稿が流れてきたときに発生するイベントです。
## `localTimeline`
ローカルタイムラインの投稿情報が流れてきます。このチャンネルにパラメータはありません。
### 流れてくるイベント一覧
#### `note`
ローカルタイムラインに新しい投稿が流れてきたときに発生するイベントです。
## `hybridTimeline`
ソーシャルタイムラインの投稿情報が流れてきます。このチャンネルにパラメータはありません。
### 流れてくるイベント一覧
#### `note`
ソーシャルタイムラインに新しい投稿が流れてきたときに発生するイベントです。
## `globalTimeline`
グローバルタイムラインの投稿情報が流れてきます。このチャンネルにパラメータはありません。
### 流れてくるイベント一覧
#### `note`
グローバルタイムラインに新しい投稿が流れてきたときに発生するイベントです。

68
src/docs/it-IT/theme.md Normal file
View File

@@ -0,0 +1,68 @@
# テーマ
テーマを設定して、Misskeyクライアントの見た目を変更できます。
## テーマの設定
設定 > テーマ
## テーマを作成する
テーマコードはJSON5で記述されたテーマオブジェクトです。 テーマは以下のようなオブジェクトです。
``` js
{
id: '17587283-dd92-4a2c-a22c-be0637c9e22a',
name: 'Danboard',
author: 'syuilo',
base: 'light',
props: {
accent: 'rgb(218, 141, 49)',
bg: 'rgb(218, 212, 190)',
fg: 'rgb(115, 108, 92)',
panel: 'rgb(236, 232, 220)',
renote: 'rgb(100, 152, 106)',
link: 'rgb(100, 152, 106)',
mention: '@accent',
hashtag: 'rgb(100, 152, 106)',
header: 'rgba(239, 227, 213, 0.75)',
navBg: 'rgb(216, 206, 182)',
inputBorder: 'rgba(0, 0, 0, 0.1)',
},
}
```
* `id` ... テーマの一意なID。UUIDをおすすめします。
* `name` ... テーマ名
* `author` ... テーマの作者
* `desc` ... テーマの説明(オプション)
* `base` ... 明るいテーマか、暗いテーマか
* `light`にすると明るいテーマになり、`dark`にすると暗いテーマになります。
* テーマはここで設定されたベーステーマを継承します。
* `props` ... テーマのスタイル定義。これから説明します。
### テーマのスタイル定義
`props`下にはテーマのスタイルを定義します。 キーがCSSの変数名になり、バリューで中身を指定します。 なお、この`props`オブジェクトはベーステーマから継承されます。 ベーステーマは、このテーマの`base`が`light`なら[_light.json5](https://github.com/syuilo/misskey/blob/develop/src/client/themes/_light.json5)で、`dark`なら[_dark.json5](https://github.com/syuilo/misskey/blob/develop/src/client/themes/_dark.json5)です。 つまり、このテーマ内の`props`に`panel`というキーが無くても、そこにはベーステーマの`panel`があると見なされます。
#### バリューで使える構文
* 16進数で表された色
* 例: `#00ff00`
* `rgb(r, g, b)`形式で表された色
* 例: `rgb(0, 255, 0)`
* `rgb(r, g, b, a)`形式で表された透明度を含む色
* 例: `rgba(0, 255, 0, 0.5)`
* 他のキーの値の参照
* `@{キー名}`と書くと他のキーの値の参照になります。`{キー名}`は参照したいキーの名前に置き換えます。
* 例: `@panel`
* 定数(後述)の参照
* `${定数名}`と書くと定数の参照になります。`{定数名}`は参照したい定数の名前に置き換えます。
* 例: `$main`
* 関数(後述)
* `:{関数名}<{引数}<{色}`
#### 定数
「CSS変数として出力はしたくないが、他のCSS変数の値として使いまわしたい」値があるときは、定数を使うと便利です。 キー名を`$`で始めると、そのキーはCSS変数として出力されません。
#### 関数
wip

View File

@@ -0,0 +1,15 @@
# タイムラインの比較
https://docs.google.com/spreadsheets/d/1lxQ2ugKrhz58Bg96HTDK_2F98BUritkMyIiBkOByjHA/edit?usp=sharing
## ホーム
自分のフォローしているユーザーの投稿
## ローカル
全てのローカルユーザーの「ホーム」指定されていない投稿
## ソーシャル
自分のフォローしているユーザーの投稿と、全てのローカルユーザーの「ホーム」指定されていない投稿
## グローバル
全てのローカルユーザーの「ホーム」指定されていない投稿と、サーバーに届いた全てのリモートユーザーの「ホーム」指定されていない投稿

View File

@@ -1,18 +1,18 @@
# Deck
デッキは利用可能なUIのひとつです。「カラム」と呼ばれるビューを複数並べて表示させることで、カスタマイズ性が高く、情報量の多いUIが構築できることが特徴です
卡片是一种可用的用户界面。它的特点是能够通过并排显示多个视图(称为 "列")来构建高度可定制和信息丰富的用户界面
## カラムの追加
デッキの背景を右クリックし、「カラムを追加」して任意のカラムを追加できます
## 列的新增
您可以在卡牌背景上点击右键单击「添加列」来新增任意的列
## カラムの移動
カラムは、ドラッグアンドドロップで他のカラムと位置を入れ替えることが出来るほか、カラムメニュー(カラムのヘッダー右クリック)から位置を移動させることもできます
## 列的移动
可以通过拖放列来与其他列互换位置,也可以从列菜单中移动列(右键单击列首)
## カラムの水平分割
カラムは左右だけでなく、上下に並べることもできます。 カラムメニューを開き、「左に重ねる」を選択すると、左のカラムの下に現在のカラムが移動します。 上下分割を解除するには、カラムメニューの「右に出す」を選択します
## 列的水平分割
列不仅可以从左到右叠加,还可以上下叠加。 如果打开列菜单,选择「向左折叠」,当前列将被移到左列下。 要解除垂直分割,请选择列菜单中的「向右弹出」
## カラムの設定
カラムメニューの「編集」を選択するとカラムの設定を編集できます。カラムの名前を変えたり、幅を変えたりできます
## 列的设置
选择列菜单的「编辑」时,可编辑当前列的设置。您可以重新命名列,或是改变列的宽度
## デッキの設定
デッキに関する設定は、[settings/deck](/settings/deck)で行えます
## Deck的设置
您可以在[settings/deck](/settings/deck)行中配置您Deck相关的设置

View File

@@ -1,2 +1,2 @@
# MFM
MFMは、Misskey Flavored Markdownの略で、Misskeyの様々な場所で使用できる専用のマークアップ言語です。 MFMで使用可能な構文は[MFMチートシート](/mfm-cheat-sheet)で確認できます
MFMMisskey Flavored Markdown的缩写是一种专用的标记语言可以用在Misskey的任何地方。 MFM中可用的语法可以在[MFMチートシート](/mfm-cheat-sheet)中找到

View File

@@ -0,0 +1,22 @@
import define from '../define';
import redis from '../../../db/redis';
import config from '../../../config';
export const meta = {
tags: ['meta'],
requireCredential: false as const,
params: {
}
};
export default define(meta, (ps, user) => {
return new Promise((res, rej) => {
redis.pubsub('numsub', config.host, (_, x) => {
res({
count: x[1]
});
});
});
});

View File

@@ -5035,10 +5035,10 @@ insert-text-at-cursor@0.3.0:
resolved "https://registry.yarnpkg.com/insert-text-at-cursor/-/insert-text-at-cursor-0.3.0.tgz#1819607680ec1570618347c4cd475e791faa25da"
integrity sha512-/nPtyeX9xPUvxZf+r0518B7uqNKlP+LqNJqSiXFEaa2T71rWIwTVXGH7hB9xO/EVdwa5/pWlFCPwShOW81XIxQ==
install-artifact-from-github@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/install-artifact-from-github/-/install-artifact-from-github-1.1.3.tgz#552f1ec3e693f970726e3f68018ff5885665ec9e"
integrity sha512-iNuncO/pI1w0UOrebs9dwwVpXqERkszPcb7AYq2hbsJDS3X+XdZ+E5kE91EBSc98mjvCMWOoBa1Zk3hVeP1ddA==
install-artifact-from-github@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/install-artifact-from-github/-/install-artifact-from-github-1.2.0.tgz#adcbd123c16a4337ec44ea76d0ebf253cc16b074"
integrity sha512-3OxCPcY55XlVM3kkfIpeCgmoSKnMsz2A3Dbhsq0RXpIknKQmrX1YiznCeW9cD2ItFmDxziA3w6Eg8d80AoL3oA==
interpret@^1.1.0:
version "1.2.0"
@@ -6579,12 +6579,7 @@ mz@^2.4.0, mz@^2.7.0:
object-assign "^4.0.1"
thenify-all "^1.0.0"
nan@^2.14.0:
version "2.14.1"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01"
integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==
nan@^2.14.2:
nan@^2.14.0, nan@^2.14.2:
version "2.14.2"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19"
integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==
@@ -8509,12 +8504,12 @@ rdf-canonize@^1.0.2:
node-forge "^0.9.1"
semver "^6.3.0"
re2@1.15.8:
version "1.15.8"
resolved "https://registry.yarnpkg.com/re2/-/re2-1.15.8.tgz#654dfbd889acc2649773a2b32dfb9feb357ca9bc"
integrity sha512-CZm4HMuNbY+LP5LjFQvBxbQmvS7iJiVR3w23Bk3jYxZFUj6wPiYRvDikyVpqHYLioVAWcgjG6F90Pk4z7ehUSg==
re2@1.15.9:
version "1.15.9"
resolved "https://registry.yarnpkg.com/re2/-/re2-1.15.9.tgz#9ed16171edcb0bc4f0e239bf55229ff3f26acbe3"
integrity sha512-AXWEhpMTBdC+3oqbjdU07dk0pBCvxh5vbOMLERL6Y8FYBSGn4vXlLe8cYszn64Yy7H8keVMrgPzoSvOd4mePpg==
dependencies:
install-artifact-from-github "^1.1.3"
install-artifact-from-github "^1.2.0"
nan "^2.14.2"
node-gyp "^7.1.2"
@@ -10025,16 +10020,11 @@ tiny-emitter@^2.0.0:
resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423"
integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==
tinycolor2@1.4.2:
tinycolor2@1.4.2, tinycolor2@^1.1.2:
version "1.4.2"
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803"
integrity sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==
tinycolor2@^1.1.2:
version "1.4.1"
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8"
integrity sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=
tmp@0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14"
@@ -10320,10 +10310,10 @@ typeorm@0.2.29:
yargonaut "^1.1.2"
yargs "^16.0.3"
typescript@4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.2.tgz#6369ef22516fe5e10304aae5a5c4862db55380e9"
integrity sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ==
typescript@4.1.3:
version "4.1.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7"
integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==
uc.micro@^1.0.1, uc.micro@^1.0.5:
version "1.0.6"
@@ -10633,10 +10623,10 @@ void-elements@^2.0.1:
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=
vue-color@2.7.1:
version "2.7.1"
resolved "https://registry.yarnpkg.com/vue-color/-/vue-color-2.7.1.tgz#ca035109ea0010f0d60b889b97d63d37ac712f2d"
integrity sha512-u3yl46B2eEej9zfAOIRRSphX1QfeNQzMwO82EIA+aoi0AKX3o1KcfsmMzm4BFkkj2ukCxLVfQ41k7g1gSI7SlA==
vue-color@2.8.1:
version "2.8.1"
resolved "https://registry.yarnpkg.com/vue-color/-/vue-color-2.8.1.tgz#a090f3dcf8ed6f07afdb865cac84b19a73302e70"
integrity sha512-BoLCEHisXi2QgwlhZBg9UepvzZZmi4176vbr+31Shen5WWZwSLVgdScEPcB+yrAtuHAz42309C0A4+WiL9lNBw==
dependencies:
clamp "^1.0.1"
lodash.throttle "^4.0.0"