Compare commits

...

197 Commits

Author SHA1 Message Date
7d70126072 Merge branch 'develop' 2019-05-16 01:18:06 +09:00
54bfffa7b9 11.14.0 2019-05-16 01:16:41 +09:00
3f5b96bf62 Resolve #4928 2019-05-16 01:07:32 +09:00
3d8bbedf1b GIFのサムネイルが生成されないのを修正
#4728
2019-05-15 21:27:20 +09:00
23c9f6a6ca Resolve #4833 2019-05-15 20:41:01 +09:00
5ba8d4949d インスタンスの設定画面を整理 2019-05-15 20:29:47 +09:00
a6befdd541 Fix bug 2019-05-15 17:05:41 +09:00
e5409db0e8 Resolve #4925 2019-05-14 23:54:39 +09:00
678d610cd6 Update CHANGELOG.md 2019-05-14 21:27:20 +09:00
466fe9c368 Merge branch 'develop' 2019-05-14 21:25:24 +09:00
13feaea7b7 11.13.0 2019-05-14 21:25:00 +09:00
e52f9301fa New Crowdin translations (#4878)
* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Spanish)

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

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

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (French)

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

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Japanese, Kansai)

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

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (French)

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

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

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

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (French)

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

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Japanese, Kansai)
2019-05-14 21:18:05 +09:00
1b58e18a6d Update dependencies 🚀 2019-05-14 21:17:29 +09:00
b779ff08e0 特定のインスタンスのファイルをすべて削除できるように 2019-05-14 21:08:35 +09:00
811f9c22d7 🎨 2019-05-14 20:57:24 +09:00
c3529f0691 Improve usability 2019-05-14 20:53:49 +09:00
f9f574532e インスタンスブロックを設定できるように 2019-05-14 20:49:09 +09:00
92dee53dd6 Update note.ts 2019-05-14 12:04:40 +09:00
5d42ee2359 Fix tag cloud on Welcome page (#4922)
Resolve #4754
2019-05-14 10:50:20 +09:00
7c03d37caa Add ToSUrl, repositoryUrl, feedbackUrl (#4921)
* Add ToSUrl, repositoryUrl, feedbackUrl

* modify nodeinfo
2019-05-14 02:57:04 +09:00
b128b593c2 Fix: user menu (#4845) (#4920)
* Fix: Firefoxで自分のメニューが開けないなど

* 自分のユーザーメニューにはミュートなどを表示しないようになど
2019-05-14 02:53:05 +09:00
342e48ed77 Fix meta tags (#4918) 2019-05-14 02:50:23 +09:00
052f8b265d Update README.md [AUTOGEN] (#4916) 2019-05-13 18:03:29 +09:00
2eedc91d74 Update Docker images on CircleCI 2019-05-12 17:27:27 +09:00
410b9ad6bc Fix: ピン留め投稿の表示順がおかしい (#4906)
* Fix: syuilo#4904

* fix comment
2019-05-12 09:37:00 +09:00
24c6dff3e4 Fix #4875 (#4899) 2019-05-11 21:43:08 +09:00
161db7636a Update log.ts 2019-05-11 10:58:34 +09:00
796252357e Merge branch 'develop' 2019-05-10 17:33:21 +09:00
b0344d52e9 11.12.0 2019-05-10 17:32:57 +09:00
8e6da3a0d9 インスタンス運営者がピン留めユーザーを設定できるように
Related #4892
2019-05-10 17:30:28 +09:00
756e4eaeec テキストのリスト内で変数埋め込みできるように 2019-05-10 16:08:01 +09:00
3126d0730a MisskeyPagesで変数を並べ替えられるように 2019-05-10 16:04:32 +09:00
748e9f15df Add notes/unrenote API 2019-05-10 15:53:53 +09:00
7c714f5788 Improve MisskeyPages 2019-05-10 14:18:18 +09:00
d3c3ad839b Update ObjectStorage example (#4890) 2019-05-10 01:46:11 +09:00
168de3c316 Resolve #4870 2019-05-09 23:27:34 +09:00
9e20fc5c88 Validate Note on createNote (#4881) 2019-05-09 15:43:31 +09:00
1ff5151786 Fix: みつけるで人気のタグが表示されない (#4883) 2019-05-09 15:42:56 +09:00
a56738a331 Update README.md [AUTOGEN] (#4877) 2019-05-07 20:55:37 +09:00
2d04a3d6d2 Merge branch 'develop' 2019-05-07 18:56:33 +09:00
e0a55b9100 11.11.2 2019-05-07 18:56:19 +09:00
0a57eecb3a New Crowdin translations (#4812)
* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (French)

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

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Norwegian)

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (German)

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

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

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

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

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

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

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

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

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

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (French)

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

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Portuguese)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

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

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

* New translations ja-JP.yml (English)

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

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (French)

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

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Norwegian)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Japanese, Kansai)

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

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

* New translations ja-JP.yml (English)

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

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

* New translations ja-JP.yml (English)

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

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (French)

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

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (English)

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

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Czech)

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

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

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (English)

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

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (French)

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

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Norwegian)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Japanese, Kansai)

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

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

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Czech)

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

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

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

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (English)
2019-05-07 18:49:51 +09:00
51f98020f6 Fix #4874 2019-05-07 18:48:38 +09:00
70123805e1 Fix #4866 2019-05-07 18:23:12 +09:00
1448b11d00 Clean up 2019-05-07 18:20:18 +09:00
490b81ed05 Fix #4873 2019-05-07 18:14:37 +09:00
96f675abed Fix: IPv4 onlyホストからDualstackホストにAP deliverできない (#4872) 2019-05-07 17:49:25 +09:00
4cd451c613 2段階認証コードの入力フォームタイプの訂正 (#4869)
Fix #4849, Resolve #4848
2019-05-07 08:45:29 +09:00
187792dfc4 Fix bug 2019-05-06 20:09:13 +09:00
3dde561fe5 Resolve #4864 (#4865) 2019-05-06 17:28:55 +09:00
a75ec45172 Merge branch 'develop' 2019-05-05 20:36:25 +09:00
3732ddf75f 11.11.1 2019-05-05 20:36:11 +09:00
b8d8097734 Fix bug 2019-05-05 20:36:09 +09:00
1092532292 Merge branch 'develop' 2019-05-05 20:33:44 +09:00
8a79ba0e2b 11.11.0 2019-05-05 20:33:29 +09:00
ca2949fbb4 MisskeyPagesにリストから選択関数を追加 2019-05-05 20:31:15 +09:00
17b373ac07 ✌️ 2019-05-05 20:16:05 +09:00
7aa66f438f Resolve #4853 2019-05-05 20:12:35 +09:00
73641fd78d Fix #4852 2019-05-05 15:17:29 +09:00
64aac9d6ad Fix #4862 2019-05-05 15:12:25 +09:00
2be13736c8 Update user-profile.ts
#4809
2019-05-05 09:42:38 +09:00
ff4f5fec1d meidg (#4835) 2019-05-05 09:29:15 +09:00
7d64f8abe4 外部サービス連携後のPackedUserがその情報を持つように (#4850) 2019-05-05 09:28:55 +09:00
88e6929e9f 外部サービス連携ログインリンクにアイコン追加 (#4858) 2019-05-05 09:28:23 +09:00
5fb0a995dd 様々な修正 (#4859)
Typo, Redundant code, Syntax error の修正
2019-05-05 09:27:55 +09:00
58a04ce1a5 ログアウトの処理と外部サービス連携Viewがセッションクッキーを作らないように (#4856) 2019-05-05 04:04:30 +09:00
f74e0d9123 Merge branch 'develop' 2019-05-04 15:21:51 +09:00
c6249b82d4 11.10.1 2019-05-04 15:21:35 +09:00
d6131c0b09 MisskeyPagesでページブロックを削除できなくなっていた問題を修正 2019-05-04 15:14:02 +09:00
e62c810b7c Use node 12 2019-05-04 14:53:46 +09:00
2851a1a7ef Update dependencies 🚀 2019-05-04 14:47:28 +09:00
12cd2709d6 Merge branch 'develop' 2019-05-03 18:58:54 +09:00
bf54e58873 11.10.0 2019-05-03 18:58:09 +09:00
6b473e3a5c Fix #4840 2019-05-03 18:55:24 +09:00
4b68abd963 割った余りを求める関数をMisskeyPagesに追加 2019-05-03 18:48:40 +09:00
0e764a2b3e Fix external service authentication (#4846) 2019-05-03 18:38:19 +09:00
9d1ed1eb0d Some import and export fixes (#4842)
* Fix: Mastodon v2.8.0 のフォローリストがインポートできない

* Fix: エクスポートリクエストに失敗してもエラーが出ない (#4821)

* エクスポートファイルでは同一ハッシュチェックをしないように
2019-05-03 18:33:25 +09:00
a09a3465a2 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2019-05-03 14:49:40 +09:00
001969efaf Improve usability 2019-05-03 14:49:22 +09:00
e7c515da9a Update README.md [AUTOGEN] (#4839) 2019-05-03 14:34:41 +09:00
8367c7dd49 Update README.md [AUTOGEN] (#4837) 2019-05-03 14:32:09 +09:00
55e6cae240 Fix #4834 2019-05-03 09:16:31 +09:00
5553c3fb17 Improve usability 2019-05-03 08:27:46 +09:00
026265cb1e Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2019-05-03 08:22:51 +09:00
289c76a802 Disable ServiceWorker 2019-05-03 08:22:44 +09:00
7c1bc1d6bc Update README.md [AUTOGEN] (#4832) 2019-05-02 19:44:59 +09:00
90cf0d32b5 Update README.md [AUTOGEN] (#4827) 2019-05-02 18:48:48 +09:00
88d934f922 Merge branch 'develop' 2019-05-02 17:57:29 +09:00
abf11bb03c 11.9.0 2019-05-02 17:57:13 +09:00
2d1f50303d Improve MisskeyPages 2019-05-02 17:55:59 +09:00
9fb7c4091f Merge branch 'develop' 2019-05-02 17:18:34 +09:00
2fdec27ab0 11.8.1 2019-05-02 17:18:11 +09:00
aff56469ed Fix bug 2019-05-02 17:15:14 +09:00
419cb7fbad Remove unwanted ! character in user token regex (#4830) 2019-05-02 06:24:32 +09:00
7882851539 Fix TypeScript semantic error (#4828)
ビルドの時こういうエラーが出てます
src/misc/aiscript/evaluator.ts(2,29): error TS7016: Could not find a declaration file for module 'seedrandom'
2019-05-01 22:56:18 +09:00
358299cf0e Merge branch 'develop' 2019-05-01 20:59:18 +09:00
5a2af24869 11.8.0-2 2019-05-01 20:58:59 +09:00
6d35872af5 Merge branch 'develop' 2019-05-01 20:57:23 +09:00
559dfdaa80 11.8.0 2019-05-01 20:56:50 +09:00
79c49bc926 ページのソースを見れるように 2019-05-01 20:48:56 +09:00
76c538ad25 🎨 2019-05-01 19:50:56 +09:00
e76e358d98 Fix bug 2019-05-01 19:50:52 +09:00
76f37671b4 🎨 2019-05-01 19:45:05 +09:00
a9fc176c3c Fix types 2019-05-01 19:31:34 +09:00
8b13e3c327 Refactor 2019-05-01 19:20:47 +09:00
c3cd6ad2d2 Refactoring 2019-05-01 18:33:11 +09:00
3444b9c9c8 Add splitStrByLine function 2019-05-01 16:33:54 +09:00
ca6fc9cd79 Remove strConcat function 2019-05-01 16:07:05 +09:00
4747ae8b61 Improve AiScript 2019-05-01 15:17:24 +09:00
b6c50d63a0 Update ja-JP.yml 2019-05-01 15:04:26 +09:00
52ebf2055e Improve AiScript 2019-05-01 14:54:34 +09:00
d0af2c2a98 Improve MisskeyPages 2019-05-01 10:37:25 +09:00
10216af48a Improve MisskeyPages 2019-05-01 10:05:33 +09:00
d0c8d537f5 Refactor 2019-05-01 09:15:29 +09:00
1903aaf351 Improve API doc
Fix #4825
2019-05-01 04:44:46 +09:00
e6cdf1b995 Fix: mention (あなた宛て) streaming にミュートが効かない (#4823) 2019-04-30 15:53:13 +09:00
2900d22cdc Update CHANGELOG.md 2019-04-30 12:38:07 +09:00
dc072d4706 Merge branch 'develop' 2019-04-30 12:21:31 +09:00
8ae14f146b 11.7.0 2019-04-30 12:20:59 +09:00
57444c6c3f Update page-editor.el.post.vue 2019-04-30 12:17:53 +09:00
759719d124 Improve MisskeyPages 2019-04-30 12:15:41 +09:00
59782973be 🎨 2019-04-30 10:08:55 +09:00
6c647ea91c Improve usability 2019-04-30 07:55:40 +09:00
c9763dabe1 変換関数を追加 2019-04-30 07:49:46 +09:00
da82754659 🎨 2019-04-30 07:43:56 +09:00
a3cc0ad18b 🎨 2019-04-30 07:41:57 +09:00
2e8e5c2751 Improve MisskeyPages
* ifブロック を追加
* ボタンやスイッチなどのテキストに変数使えるようにした
2019-04-30 06:40:02 +09:00
a60d83b101 Fix ogp 2019-04-29 18:15:12 +09:00
6d45265763 Use bigint 2019-04-29 17:38:31 +09:00
42e84b77e1 Merge branch 'develop' 2019-04-29 15:26:43 +09:00
24121cfadb 11.6.0 2019-04-29 15:26:09 +09:00
93093dd288 🎨 2019-04-29 15:20:37 +09:00
53381c04e6 🎨 2019-04-29 15:17:31 +09:00
c6b64e57f1 いくつかの文字列関数を追加 2019-04-29 15:13:04 +09:00
9158426d0a Improve usability 2019-04-29 14:51:04 +09:00
cef26853df Improve usability 2019-04-29 14:46:35 +09:00
c0673884c5 🎨 2019-04-29 14:38:06 +09:00
c98eb64598 Fix bug 2019-04-29 14:37:58 +09:00
8836bd4f3b Merge branch 'develop' 2019-04-29 11:11:17 +09:00
a58df29208 11.5.1 2019-04-29 11:10:59 +09:00
0d64a17d86 Update page.vue 2019-04-29 11:10:50 +09:00
c886c09cdb MisskeyPagesで値が0の変数が表示されない問題を修正 2019-04-29 11:08:35 +09:00
e86d0007c6 Fix error 2019-04-29 11:03:05 +09:00
624ee76e71 Fix bug 2019-04-29 11:00:41 +09:00
9406079cb7 Merge branch 'develop' 2019-04-29 09:29:48 +09:00
cd2de7f893 11.5.0 2019-04-29 09:29:21 +09:00
342061803e Update dependencies 🚀 2019-04-29 09:28:13 +09:00
05b8111c19 Pages (#4811)
* wip

* wip

* wip

* Update page-editor.vue

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* Update page-editor.variable.core.vue

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* Update aiscript.ts

* wip

* Update package.json

* wip

* wip

* wip

* wip

* wip

* Update page.vue

* wip

* wip

* wip

* wip

* more info

* wip fn

* wip

* wip

* wip
2019-04-29 09:11:57 +09:00
747a0b1791 Update define.ts 2019-04-28 19:56:41 +09:00
c05586b53a Improve performance 2019-04-27 11:17:03 +09:00
0cfca4a618 Fix official instance address (#4805)
いくつかのURLが misskey.xyz になってたままだったので misskey.io に訂正
2019-04-26 18:29:56 +09:00
2b8187f7ab Fix bug 2019-04-26 00:54:11 +09:00
291e7e7943 おすすめユーザーに自分自身を含まないように (#4803)
Fix #4790
2019-04-26 00:52:58 +09:00
535d10f469 Improve API console 2019-04-25 14:40:42 +09:00
4cb58c0892 Refactor 2019-04-25 13:27:07 +09:00
6721d27e3f Improve hashtag API 2019-04-25 13:25:10 +09:00
da9dd7c423 Improve API definition 2019-04-25 12:56:52 +09:00
867eb41618 Fix #4415 2019-04-25 12:37:13 +09:00
6fdff13480 Update example.yml 2019-04-25 12:24:18 +09:00
e581ead1ed Update CHANGELOG.md 2019-04-25 12:22:03 +09:00
7495206db2 Merge branch 'develop' 2019-04-25 07:48:29 +09:00
fe87d16d46 11.4.0 2019-04-25 07:48:12 +09:00
0db54386cd Resolve #3119 2019-04-25 07:46:39 +09:00
772258b0b8 Fix #4793 2019-04-25 04:32:01 +09:00
3ef002e14d Fix bug 2019-04-25 04:27:34 +09:00
b90d473ae5 Fix layout 2019-04-25 04:26:58 +09:00
f5091d524b Refactorgin 2019-04-25 04:17:03 +09:00
ee5720df2c Fix #4704 (#4797)
*  Fix #4632

* Fix #4795
2019-04-25 04:07:39 +09:00
afe2037985 Merge branch 'develop' 2019-04-24 20:51:34 +09:00
878cd18144 11.3.1 2019-04-24 20:51:14 +09:00
e8c8f67a09 Update post-form.vue
Close #4792

Co-Authored-By: tamaina <tamaina@hotmail.co.jp>
2019-04-24 20:47:47 +09:00
7b29e7cf7e Fix bug 2019-04-24 20:41:32 +09:00
723d3e6871 Merge branch 'develop' 2019-04-24 15:23:48 +09:00
f063dee12a 11.3.0 2019-04-24 15:23:31 +09:00
db4b315d3d Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2019-04-24 15:21:58 +09:00
64d00b08a3 Improve announcement
* お知らせにMFMを使えるように
* お知らせに画像を添付できるように
2019-04-24 15:21:39 +09:00
74736a941e Update README.md [AUTOGEN] (#4778) 2019-04-24 14:56:23 +09:00
c40366f20a Update README.md [AUTOGEN] (#4777) 2019-04-24 14:55:49 +09:00
d73e52ac2a Create find-by-hash.ts 2019-04-24 14:54:19 +09:00
9fac8a611f Fix response 2019-04-24 14:54:15 +09:00
9c774a50f8 Update attached-notes.ts 2019-04-24 14:54:06 +09:00
4f20ee1909 Rename theme 2019-04-24 14:44:28 +09:00
1440c5bc65 Fix bug 2019-04-24 14:39:59 +09:00
5829b2a7c1 Update CHANGELOG.md 2019-04-24 10:07:27 +09:00
e3c4bc18d0 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2019-04-24 10:02:49 +09:00
8555ec2f72 Fix #4767 2019-04-24 10:02:31 +09:00
8d7cefbbbe New Crowdin translations (#4771)
* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Chinese Simplified)
2019-04-24 09:54:43 +09:00
5aa5896b22 Cache meta 2019-04-24 08:11:19 +09:00
8a55bdd89d Increase reaction column length 2019-04-24 03:39:11 +09:00
6444ef6444 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2019-04-24 03:26:10 +09:00
701ab6cc68 Refactor 2019-04-24 03:26:02 +09:00
3c6ce7a943 Update README.md [AUTOGEN] (#4773) 2019-04-24 00:34:48 +09:00
1e54afd217 Update README.md [AUTOGEN] (#4772) 2019-04-24 00:33:55 +09:00
4e90fd3a06 メンテナ名を必須でなくす
Close #4753
2019-04-23 22:48:53 +09:00
0463c6bb0f Refactor API (#4770)
* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* Update description.ts

* wip
2019-04-23 22:35:26 +09:00
f31f986d66 Fix #4768 2019-04-23 02:50:59 +09:00
c203c8302b Add @rinsuki into collaborators (#4762) 2019-04-22 18:19:20 +09:00
346 changed files with 9852 additions and 2194 deletions

View File

@ -4,8 +4,9 @@ executors:
default:
working_directory: /tmp/workspace
docker:
- image: misskey/ci:latest
- image: misskey/ci:v11-node11
- image: circleci/redis:latest
- image: circleci/postgres:latest
docker:
working_directory: /tmp/workspace
docker:

View File

@ -6,8 +6,6 @@ mongodb:
db: misskey
user: syuilo
pass: ''
drive:
storage: 'db'
redis:
host: localhost
port: 6379

View File

@ -6,8 +6,6 @@ mongodb:
db: test-misskey
user: admin
pass: ''
drive:
storage: 'db'
# __REDIS__
redis:
host: localhost

View File

@ -78,47 +78,6 @@ redis:
# port: 9200
# pass: null
# ┌────────────────────────────────────┐
#───┘ File storage (Drive) configuration └──────────────────────
drive:
storage: 'fs'
# OR
# storage: 'minio'
# bucket:
# prefix:
# config:
# endPoint:
# port:
# useSSL:
# accessKey:
# secretKey:
# S3 example
# storage: 'minio'
# bucket: bucket-name
# prefix: files
# config:
# endPoint: s3-us-west-2.amazonaws.com
# region: us-west-2
# useSSL: true
# accessKey: XXX
# secretKey: YYY
# S3 example (with CDN, custom domain)
# storage: 'minio'
# bucket: drive.example.com
# prefix: files
# baseUrl: https://drive.example.com
# config:
# endPoint: s3-us-west-2.amazonaws.com
# region: us-west-2
# useSSL: true
# accessKey: XXX
# secretKey: YYY
# ┌───────────────┐
#───┘ ID generation └───────────────────────────────────────────
@ -132,6 +91,9 @@ drive:
# ulid ... Millisecond accuracy
# objectid ... This is left for backward compatibility
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
# ID SETTINGS AFTER THAT!
id: 'aid'
# ┌─────────────────────┐
@ -146,3 +108,6 @@ autoAdmin: true
# Clustering
#clusterLimit: 1
# IP address family used for outgoing request (ipv4, ipv6 or dual)
#outgoingAddressFamily: ipv4

4
.github/CODEOWNERS vendored
View File

@ -1,7 +1,7 @@
# PATH OWNERS
/.autogen/ @acid-chicken
/.circleci/ @syuilo @acid-chicken
/.config/ @syuilo @AyaMorisawa @mei23 @acid-chicken
/.config/ @syuilo @AyaMorisawa @mei23 @acid-chicken @rinsuki
# /.config/mongo_initdb_example.js @khws4v1
/.github/ @syuilo @AyaMorisawa @acid-chicken
/.vscode/ @acid-chicken
@ -12,7 +12,7 @@
# /docs/*.fr.md @BoFFire
# /docs/docker.*.md @khws4v1
/locales/ @syuilo
/src/ @syuilo @AyaMorisawa @mei23 @acid-chicken
/src/ @syuilo @AyaMorisawa @mei23 @acid-chicken @rinsuki
# /src/crypto_key.cc @akihikodaki
# /src/crypto_key.d.ts @akihikodaki
/.dockerignore @syuilo # @khws4v1

1
.gitignore vendored
View File

@ -20,3 +20,4 @@ api-docs.json
yarn.lock
.DS_Store
/files
ormconfig.json

View File

@ -1 +1 @@
v11.7.0
v12.1.0

View File

@ -5,8 +5,27 @@ If you encounter any problems with updating, please try the following:
1. `npm run clean` or `npm run cleanall`
2. Retry update (Don't forget `npm i`)
Migration
------------------------------
#### 1
```
npm i -g ts-node
```
#### 2
```
npm run migrate
```
How to migrate to v11 from v10
------------------------------
### 移行の注意点
**以下のデータは引き継がれません**
* 通知
* リモートの投稿
* リバーシの対局
### 手順
1. v11をインストールしたい場所に syuilo/misskey をクローン
2. config を設定する
* PostgreSQL(`db`)の設定とは別に、v10からMongoDBの設定をコピペしてくる(例は下にあります)
@ -35,29 +54,254 @@ mongodb:
8. master ブランチに戻す
9. enjoy
11.14.0 (2019/05/16)
--------------------
### 注意
このバージョンからオブジェクトストレージの設定は設定ファイルではなく管理画面から行うようになりました。
オブジェクトストレージを使用している場合、アップデートした後管理画面にアクセスしオブジェクトストレージの設定を再度行ってください。
### ✨Improvements
* 特定のユーザーのファイルをすべて削除できるように
* インスタンスの設定画面を整理
### 🐛Fixes
* GIF画像のサムネイルが生成されないのを修正
* 管理画面の「ログ」で複数の除外条件を設定できない問題を修正
11.13.0 (2019/05/14)
--------------------
### 注意
このアップデートを適用した後、プロセスを起動(もしくは再起動)する前に[マイグレーション](#migration)の手順を実行してください
### ✨Improvements
* 利用規約URL、リポジトリURL、フィードバックURLを設定できるように
* 特定のインスタンスのファイルをすべて削除できるように
* _blankで外部リンクされる可能性がある箇所にnoopenerを追加
* ユーザーや外部インスタンスが生成するリンクにnofollowを追加
* リモートのユーザーページやートページにnoindexを追加
* 自分のユーザーメニューにはミュートなどを表示しないように
* デザインの調整
### 🐛Fixes
* インスタンスブロックを設定できない問題を修正
* ピン留め投稿の表示順がおかしい問題を修正
* 設定の「アップデートを確認」でメッセージが正しく表示されない問題を修正
* Firefoxで自分のメニューが開けない問題を修正
* Welcomeページのタグクラウドが動かない問題を修正
11.12.0 (2019/05/10)
--------------------
### 注意
このアップデートを適用した後、プロセスを起動(もしくは再起動)する前に[マイグレーション](#migration)の手順を実行してください
### ✨ Improvements
* インスタンス運営者がおすすめアカウントを設定できるように
* MisskeyPagesでNAME環境変数がNULLにならないように
* MisskeyPagesにNULL環境変数を追加
* MisskeyPagesで変数を並べ替えられるように
* MisskeyPagesのテキストのリスト内で変数埋め込みできるように
* 自分の指定した投稿のRenoteを全て解除するAPIを追加
### 🐛Fixes
* Noteをpull取得した時にhost名がvalidateされていない問題を修正
* みつけるで人気のタグが表示されない問題を修正
### その他
* アカウントのisVerifiedフラグを廃止
11.11.2 (2019/05/07)
--------------------
### 🐛Fixes
* IPv4 onlyホストからDualstackホストにAP deliverできない問題を修正
* ストリーミングに接続するまでラグがある問題を修正
* 2段階認証のコードが0から始まる時正しく入力できない問題を修正
* ユーザーの更新日時が新しい順で更新日時がnullのユーザーが先頭に来る問題を修正
* 値選択時の問題を修正
* リバーシでマップの変更が反映されない問題を修正
* リバーシで対局終了直後に盤面を巻き戻してもすぐ最終ターンまでリセットされる問題を修正
11.11.1 (2019/05/05)
--------------------
### 🐛Fixes
* MisskeyPagesのリストから選択関数が使えない問題を修正
11.11.0 (2019/05/05)
--------------------
### ✨ Improvements
* MisskeyPagesにリストから選択関数を追加
* MisskeyPagesに確率を指定できるテキストランダム選択関数を追加
* 外部サービス連携ログインリンクにアイコン追加
### 🐛Fixes
* MisskeyPagesでifを入れ子にできなくなっていた問題を修正
* MisskeyPagesで数値入力を作成するとテキスト入力になる問題を修正
* 外部サービス連携に関する問題を修正
11.10.1 (2019/05/04)
--------------------
### 🐛Fixes
* MisskeyPagesでページブロックを削除できなくなっていた問題を修正
### その他
* Node.js v12対応
11.10.0 (2019/05/03)
--------------------
### 注意
このアップデートを適用した後、プロセスを起動(もしくは再起動)する前に[マイグレーション](#migration)の手順を実行してください
### ✨ Improvements
* MisskeyPagesに割った余りを求める関数を追加
* Mastodon v2.8.0 のフォローリストをインポートできるように
* エクスポートリクエストに失敗したらエラーを表示するように
* エクスポートファイルでは同一ハッシュチェックをしないように
### 🐛Fixes
* 2段階認証を設定するとログインできなくなる問題を修正
* ファイルをアップロードできないことがある問題を修正
* リモートファイルをキャッシュしない設定だとサムネイル時にオリジナル画像が表示されない問題を修正
* 外部サービス連携の不具合を修正
11.9.0 (2019/05/02)
-------------------
### ✨ Improvements
* MisskeyPagesで編集時にページブロックをドラッグで並べ替えられるように
* MisskeyPagesにカウンターボタンブロックを追加
11.8.1 (2019/05/02)
-------------------
### 🐛Fixes
* リモートファイルをキャッシュしないオプション有効時にファイルが作成できない問題を修正
11.8.0-2 (2019/05/01)
-------------------
* 11.8.0 のリリース内容が 11.7.0 と同一だったのを修正
11.8.0 (2019/05/01)
-------------------
### ✨ Improvements
* MisskeyPagesで関数を作成できるように
* MisskeyPagesでソースを表示できるように
* MisskeyPagesにシードを与えるランダム関数を追加
* MisskeyPagesに複数行テキストをテキストのリストに変換する関数を追加
### 🐛Fixes
* APIドキュメントが見れなくなっていたのを修正
* mention (あなた宛て) streaming にミュートが効かない問題を修正
* デザインの調整
11.7.0 (2019/04/30)
-------------------
### ✨ Improvements
* MisskeyPagesに ifブロック を追加
* MisskeyPagesに テキストエリア を追加
* MisskeyPagesに 複数行テキスト入力 を追加
* MisskeyPagesに 投稿フォーム を追加
* MisskeyPagesに 変換系関数 を追加
* MisskeyPagesに 環境変数 URL を追加
* MisskeyPagesでボタンやスイッチなどのテキストに変数使えるように
### 🐛Fixes
* OGPのサイト名を修正
* デザインの調整
11.6.0 (2019/04/29)
-------------------
### ✨ Improvements
* AiScriptにいくつかの文字列操作関数を追加
* ページ編集画面にページへのリンクを表示するように
### 🐛Fixes
* MisskeyPagesで数値入力が文字列として扱われる問題を修正
* デザインの調整
11.5.1 (2019/04/29)
-------------------
### 🐛Fixes
* MisskeyPagesで環境変数を別の変数内で使えない問題を修正
* MisskeyPagesで値が0の変数が表示されない問題を修正
11.5.0 (2019/04/29)
-------------------
### 注意
このアップデートを適用した後、プロセスを起動(もしくは再起動)する前に[マイグレーション](migration)の手順を実行してください
### New features
#### MisskeyPages
ページ(記事)を作成できるように。
* 後から何度でも編集できる
* アイキャッチを設定できる
* フォントを設定できる
* 画像を好きな位置に挿入できる
* URLを決められる
* タイトルを設定できる
* 見出しを設定できる
* ページの要約を設定できる(URLプレビュー時などに便利)
* 変数や式(aka AiScript)を使用して動的なページも作れる
* 目次自動生成(coming soon)
ページを気に入ったら「いいね」しよう (coming soon)
### ✨ Improvements
* APIコンソールでパラメータテンプレートを表示するように
### 🐛Fixes
* おすすめユーザーに自分自身が含まれる問題を修正
* ユーザーサジェストで表示名が変わらない問題を修正
11.4.0 (2019/04/25)
-------------------
### ✨ Improvements
* 検索でローカルの投稿のみに絞れるように
* 検索で特定のインスタンスの投稿のみに絞れるように
* 検索で特定のユーザーの投稿のみに絞れるように
### 🐛Fixes
* 投稿が増殖する問題を修正
* ストリームで過去の投稿が流れてくる問題を修正
* モバイル版のユーザーページで遷移してもユーザー名が変わらない問題を修正
* お知らせを切り替えても内容が変わらない問題を修正
11.3.1 (2019/04/24)
-------------------
### 🐛Fixes
* Webからファイルがアップロードできない問題を修正
11.3.0 (2019/04/24)
-------------------
### ✨ Improvements
* お知らせにMFMを使えるように
* お知らせに画像を添付できるように
### 🐛Fixes
* 投稿のタグ検索APIで大文字小文字が区別されていたのを修正
* 公開範囲がホームの投稿がグローバルTLに流れる問題を修正
* モバイルビューの投稿詳細にて acct が長いとアイコンが圧迫面接される問題を修正
11.2.2 (2019/04/22)
-------------------
### Fixes
### 🐛Fixes
* 2段階認証を有効にするとログインできない問題を修正
* リモートユーザーの修復処理が自動的に実行されない問題を修正
* リモートユーザー情報が更新されない問題を修正
11.2.1 (2019/04/21)
-------------------
### Fixes
### 🐛Fixes
* MEIDが25桁になっているのを修正
* リモートユーザー情報が更新されない問題を修正
11.2.0 (2019/04/18)
-------------------
### Improvements
### Improvements
* 検索で日付(日時)を入力するとタイムラインをその時点まで遡るように
* APIコンソールでエンドポイントをサジェストするように
* モバイル版でドライブのメニューを使いやすく
* サイレンス時に確認を表示するように
* ユーザーメニューでブロックなどの操作を行う時に確認するように
### Fixes
### 🐛Fixes
* アプリケーション連携画面でパーミッションが表示されない問題を修正
* アンケートウィジットでもMFMを使用するように
* フォローしてないユーザーのホーム投稿がSTLに流れてくる問題を修正
@ -66,7 +310,7 @@ mongodb:
11.1.6 (2019/04/18)
-------------------
### Fixes
### 🐛Fixes
* 未認知ユーザーからActivityが飛んできた場合に処理できない問題を修正
* その投稿を見たのにも関わらずメンションインジケーターが点灯し続ける問題を修正
* ハッシュタグの判定を改善
@ -74,14 +318,14 @@ mongodb:
11.1.5 (2019/04/17)
-------------------
### Fixes
### 🐛Fixes
* ユーザー名に含まれているカスタム絵文字が表示されないことがある問題を修正
* 壁紙の設定ができない問題を修正
* デザインの調整
11.1.4 (2019/04/17)
-------------------
### Fixes
### 🐛Fixes
* タイムライン取得時に削除されたファイルを添付している投稿が含まれているとサーバーでエラーになる問題を修正
* 管理画面のインスタンスメニューで変更前の設定が読み込まれないことがある問題を修正
* 猫ではないのに猫のままで表示される問題を修正
@ -91,12 +335,12 @@ mongodb:
11.1.3 (2019/04/16)
-------------------
### Fixes
### 🐛Fixes
* アプリからAPIにリクエストするときにランダムなユーザーがリクエストしたことになる問題を修正
11.1.2 (2019/04/15)
-------------------
### Fixes
### 🐛Fixes
* 画像描画の依存関係を変更
* リモートユーザーのファイルを削除するときに古い方からではなく新しい方から削除されるのを修正
* リアクションしてないのにリアクションしたことになる問題を修正
@ -104,25 +348,25 @@ mongodb:
11.1.1 (2019/04/15)
-------------------
### Fixes
### 🐛Fixes
* Metaタグの application-name を Misskey で固定するように修正
* トークメッセージが既読にならない問題を修正
* デフォルトでHTLを表示するように
11.1.0 (2019/04/15)
-------------------
### Improvements
### Improvements
* アイコン未設定時にランダムな画像を表示するように
* 管理者やモデレーターはレートリミット無効に
### Fixes
### 🐛Fixes
* メンションの「あなた」インジケーターが表示されない問題を修正
* ブロックAPIでエラーが発生する問題を修正
* プッシュ通知の購読に失敗する問題を修正
11.0.3 (2019/04/15)
-------------------
### Fixes
### 🐛Fixes
* ハッシュタグ検索APIが動作しない問題を修正
* モデレーターなのにアカウントメニューに「管理」が表示されない問題を修正
* プッシュ通知の購読に失敗する問題を修正
@ -130,7 +374,7 @@ mongodb:
11.0.2 (2019/04/15)
-------------------
### Fixes
### 🐛Fixes
* アプリが作成できない問題を修正
* 「ハイライト」が表示されない問題を修正
* リモートの投稿に添付されている画像が小さい問題を修正
@ -139,19 +383,19 @@ mongodb:
11.0.1 (2019/04/15)
-------------------
### Improvements
### Improvements
* 不要な依存関係を削除
11.0.0 daybreak (2019/04/14)
----------------------------
### Improvements
### Improvements
* **データベースがMongoDBからPostgreSQLに変更されました**
* **Redisが必須に**
* アカウントを完全に削除できるように
* 投稿フォームで添付ファイルの閲覧注意を確認/設定できるように
* ミュート/ブロック時にそのユーザーの投稿のウォッチをすべて解除するように
### Fixes
### 🐛Fixes
* フォロー申請数が実際より1すくなくなる問題を修正
* リストからアカウント削除したユーザーを削除できない問題を修正
* リストTLでフォローしていないユーザーの非公開投稿が流れる問題を修正

View File

@ -197,3 +197,13 @@ const user = await Users.findOne(userId).then(ensure);
// }
// の糖衣構文のような扱いです
```
### Migration作成方法
コードの変更をした後、`ormconfig.json``npm run ormconfig`で生成)を用意し、
```
npm i -g ts-node
ts-node ./node_modules/typeorm/cli.js migration:generate -n 変更の名前
```
作成されたスクリプトは不必要な変更を含むため除去してください。

View File

@ -1,4 +1,4 @@
FROM node:11-alpine AS base
FROM node:12.1-alpine AS base
ENV NODE_ENV=production

View File

@ -1,6 +1,6 @@
<a href="https://xn--931a.moe/"><img src="https://github.com/syuilo/misskey/blob/develop/assets/ai-orig.png?raw=true" align="right" height="320px"/></a>
[![Misskey](/assets/title.png)](https://misskey.xyz/)
[![Misskey](/assets/title.png)](https://misskey.io/)
================================================================
[![CircleCI](https://img.shields.io/circleci/project/github/syuilo/misskey.svg?style=for-the-badge&logo=circleci)](https://circleci.com/gh/syuilo/misskey)
@ -10,7 +10,7 @@
**A forever evolving, sophisticated microblogging platform.**
<p align="justify">
<a href="https://misskey.xyz">Misskey</a> is a decentralized microblogging platform born on Earth.
<a href="https://misskey.io">Misskey</a> is a decentralized microblogging platform born on Earth.
Since it exists within the Fediverse (a universe where various social media platforms are organized),
it is mutually linked with other social media platforms.
Why don't you take a short break from the hustle and bustle of the city, and dive into a new Internet? <a href="https://joinmisskey.github.io/">Find an instance!</a>
@ -88,12 +88,14 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
<td><img src="https://avatars0.githubusercontent.com/u/10798641?s=460&v=4" alt="AyaMorisawa" width="100"></td>
<td><img src="https://avatars1.githubusercontent.com/u/30769358?s=460&v=4" alt="mei23" width="100"></td>
<td><img src="https://avatars2.githubusercontent.com/u/20679825?s=460&v=4" alt="acid-chicken" width="100"></td>
<td><img src="https://avatars2.githubusercontent.com/u/6533808?s=460&v=4" alt="rinsuki" width="100"></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/syuilo">@syuilo</a></td>
<td align="center"><a href="https://github.com/AyaMorisawa">@AyaMorisawa</a></td>
<td align="center"><a href="https://github.com/mei23">@mei23</a></td>
<td align="center"><a href="https://github.com/acid-chicken">@acid-chicken</a></td>
<td align="center"><a href="https://github.com/rinsuki">@rinsuki</a></td>
</tr>
</table>
@ -102,70 +104,76 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
<!-- PATREON_START -->
<table><tr>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5888816/36da0f7c15954df0ab13f9abdf227f66/1.jpeg?token-time=2145916800&token-hash=at8QpJXJ8C0zINY_NmoMKv-MhXVoUK-YzTgaJPJzJYU%3D" alt="Hiroshi Seki" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12190916/fb7fa7983c14425f890369535b1506a4/3.png?token-time=2145916800&token-hash=oH_i7gJjNT7Ot6j9JiVwy7ZJIBqACVnzLqlz4YrDAZA%3D" alt="weep" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12190916/fb7fa7983c14425f890369535b1506a4/3.png?token-time=2145916800&token-hash=oH_i7gJjNT7Ot6j9JiVwy7ZJIBqACVnzLqlz4YrDAZA%3D" alt="weepjp" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/19045173/cb91c0f345c24d4ebfd05f19906d5e26/1.png?token-time=2145916800&token-hash=o_zKBytJs_AxHwSYw_5R8eD0eSJe3RoTR3kR3Q0syN0%3D" alt="kiritan" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13099460/43cecdbaa63a40d79bf50a96b9910b9d/1.jpe?token-time=2145916800&token-hash=bqwLTk0Wo0hUJJ8J5y7ii05bLzz-_CDA7Bo0Mp4RFU0%3D" alt="ne_moni" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12913507/f7181eacafe8469a93033d85f5969c29/4.jpe?token-time=2145916800&token-hash=zEyJqVM7u9d8Ri-65fJYSJcWF1jBH1nJ5a3taRzrTmw%3D" alt="Melilot" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5670915/ee175f0bfb6347ffa4ea101a8c097bff/1.jpg?token-time=2145916800&token-hash=mPLM9CA-riFHx-myr3bLZJuH2xBRHA9se5VbHhLIOuA%3D" alt="osapon" width="100"></td>
<td><img src="https://c8.patreon.com/2/200/16869916" alt="見当かなみ" width="100"></td>
</tr><tr>
<td><a href="https://www.patreon.com/rane_hs">Hiroshi Seki</a></td>
<td><a href="https://www.patreon.com/weepjp">weep</a></td>
<td><a href="https://www.patreon.com/weepjp">weepjp</a></td>
<td><a href="https://www.patreon.com/user?u=19045173">kiritan</a></td>
<td><a href="https://www.patreon.com/user?u=13099460">ne_moni</a></td>
<td><a href="https://www.patreon.com/user?u=12913507">Melilot</a></td>
<td><a href="https://www.patreon.com/osapon">osapon</a></td>
<td><a href="https://www.patreon.com/user?u=16869916">見当かなみ</a></td>
</tr></table>
<table><tr>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/18899730/6a22797f68254034a854d69ea2445fc8/1.png?token-time=2145916800&token-hash=b_uj57yxo5VzkSOUS7oXE_762dyOTB_oxzbO6lFNG3k%3D" alt="YuzuRyo61" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12021162/963128bb8d14476dbd8407943db8f31a/1.png?token-time=2145916800&token-hash=FMV7cPKBD1TU2WTbl1jg6AcdKSvTb2BSFcDhgc-EO8w%3D" alt="gutfuckllc" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/11357794/923ce94cd8c44ba788ee931907881839/1.png?token-time=2145916800&token-hash=9nEQje_eMvUjq9a7L3uBqW-MQbS-rRMaMgd7UYVoFNM%3D" alt="mydarkstar" width="100"></td>
<td><img src="https://c8.patreon.com/2/200/12718187" alt="Peter G." width="100"></td>
<td><img src="https://c8.patreon.com/2/200/18833336" alt="itiradi" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13039004/509d0c412eb14ae08d6a812a3054f7d6/1.jpe?token-time=2145916800&token-hash=UQRWf01TwHDV4Cls1K0YAOAjM29ssif7hLVq0ESQ0hs%3D" alt="nemu" width="100"></td>
<td><img src="https://c8.patreon.com/2/200/17866454" alt="sikyosyounin" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5881381/6235ca5d3fb04c8e95ef5b4ff2abcc18/3.png?token-time=2145916800&token-hash=KjfQL8nf3AIf6WqzLshBYAyX44piAqOAZiYXgZS_H6A%3D" alt="YUKIMOCHI" width="100"></td>
<td><img src="https://c8.patreon.com/2/200/17463605" alt="Sampot" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/19356899/496b4681d33b4520bd7688e0fd19c04d/1.jpeg?token-time=2145916800&token-hash=3aMtpAjhwf01G3Uf8iIKYL8FUXXgxV7NvoQLne7lAKE%3D" alt="Ryosuke Yamamoto" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13737140/1adf7835017d479280d90fe8d30aade2/1.png?token-time=2145916800&token-hash=0pdle8h5pDZrww0BDOjdz6zO-HudeGTh36a3qi1biVU%3D" alt="Satsuki Yanagi" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/19356899/496b4681d33b4520bd7688e0fd19c04d/2.jpeg?token-time=2145916800&token-hash=_sTj3dUBOhn9qwiJ7F19Qd-yWWfUqJC_0jG1h0agEqQ%3D" alt="sheeta.s" width="100"></td>
</tr><tr>
<td><a href="https://www.patreon.com/Yuzulia">YuzuRyo61</a></td>
<td><a href="https://www.patreon.com/gutfuckllc">gutfuckllc</a></td>
<td><a href="https://www.patreon.com/mydarkstar">mydarkstar</a></td>
<td><a href="https://www.patreon.com/user?u=12718187">Peter G.</a></td>
<td><a href="https://www.patreon.com/user?u=18833336">itiradi</a></td>
<td><a href="https://www.patreon.com/user?u=13039004">nemu</a></td>
<td><a href="https://www.patreon.com/user?u=17866454">sikyosyounin</a></td>
<td><a href="https://www.patreon.com/yukimochi">YUKIMOCHI</a></td>
<td><a href="https://www.patreon.com/user?u=17463605">Sampot</a></td>
<td><a href="https://www.patreon.com/user?u=19356899">Ryosuke Yamamoto</a></td>
<td><a href="https://www.patreon.com/user?u=13737140">Satsuki Yanagi</a></td>
<td><a href="https://www.patreon.com/user?u=19356899">sheeta.s</a></td>
</tr></table>
<table><tr>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13737140/1adf7835017d479280d90fe8d30aade2/1.png?token-time=2145916800&token-hash=0pdle8h5pDZrww0BDOjdz6zO-HudeGTh36a3qi1biVU%3D" alt="Satsuki Yanagi" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/17880724/311738c8a48f4a6b9443c2445a75adde/1.jpe?token-time=2145916800&token-hash=CPxGQhKIlEaa6WUcgbyHixyKEhakiw9RFdOhsIJBQ_o%3D" alt="takimura" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/17195955/be45e5e14c3e48b2bee0456c84e19df4/4.jpe?token-time=2145916800&token-hash=UslrPVM-8TXOe8AapuNiaFYjcIJgPNcU-fKpGbfGJNI%3D" alt="Damillora" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/16900731/83884b38afc74d4cbe83c30a13b10edd/1.png?token-time=2145916800&token-hash=R5Tog8RWg0rguRoCIoir3lThokrdPvs8Utfikhc0nhY%3D" alt="Atsuko Tominaga" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/4389829/9f709180ac714651a70f74a82f3ffdb9/3.png?token-time=2145916800&token-hash=FTm3WVom4dJ9NwWMU4OpCL_8Yc13WiwEbKrDPyTZTPs%3D" alt="natalie" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13034746/c711c7f58e204ecfbc2fd646bc8a4eee/1.jpe?token-time=2145916800&token-hash=EWxXhVbZYH7KB4IDT3joc8TbIg8zPO40x1r5IDn3R7c%3D" alt="Hiratake" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5923936/2a743cbfbff946c2af3f09026047c0da/2.png?token-time=2145916800&token-hash=h6yphW1qnM0n_NOWaf8qtszMRLXEwIxfk5beu4RxdT0%3D" alt="noellabo" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/2384390/5681180e1efb46a8b28e0e8d4c8b9037/1.jpg?token-time=2145916800&token-hash=SJcMy-Q1BcS940-LFUVOMfR7-5SgrzsEQGhYb3yowFk%3D" alt="CG" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/18072312/98e894d960314fa7bc236a72a39488fe/1.jpe?token-time=2145916800&token-hash=qA8j97lIZNc-74AuZ0p4F3ms6sKPeKjtNt2vEuwpsyo%3D" alt="Hekovic" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/4503830/ccf2cc867ea64de0b524bb2e24b9a1cb/1.jpeg?token-time=2145916800&token-hash=L55UhJ0rcuNAH3w_ryeeGN4hC6taoOixyAhraEi0bzw%3D" alt="dansup" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/619786/32cf01444db24e578cd1982c197f6fc6/1.jpeg?token-time=2145916800&token-hash=d8jBQLMOHD87KtXs5C9fk1o58DMF73pQ-dYH3uZJPBE%3D" alt="Gargron" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5731881/4b6038e6cda34c04b83a5fcce3806a93/1.png?token-time=2145916800&token-hash=hBayGfOmQH3kRMdNnDe4oCZD_9fsJWSt29xXR3KRMVk%3D" alt="Nokotaro Takeda" width="100"></td>
</tr><tr>
<td><a href="https://www.patreon.com/user?u=13737140">Satsuki Yanagi</a></td>
<td><a href="https://www.patreon.com/takimura">takimura</a></td>
<td><a href="https://www.patreon.com/damillora">Damillora</a></td>
<td><a href="https://www.patreon.com/user?u=16900731">Atsuko Tominaga</a></td>
<td><a href="https://www.patreon.com/user?u=4389829">natalie</a></td>
<td><a href="https://www.patreon.com/hiratake">Hiratake</a></td>
<td><a href="https://www.patreon.com/noellabo">noellabo</a></td>
<td><a href="https://www.patreon.com/Corset">CG</a></td>
<td><a href="https://www.patreon.com/hekovic">Hekovic</a></td>
<td><a href="https://www.patreon.com/dansup">dansup</a></td>
<td><a href="https://www.patreon.com/mastodon">Gargron</a></td>
<td><a href="https://www.patreon.com/takenoko">Nokotaro Takeda</a></td>
</tr></table>
<table><tr>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/619786/32cf01444db24e578cd1982c197f6fc6/1.jpeg?token-time=2145916800&token-hash=d8jBQLMOHD87KtXs5C9fk1o58DMF73pQ-dYH3uZJPBE%3D" alt="Gargron" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5731881/4b6038e6cda34c04b83a5fcce3806a93/1.png?token-time=2145916800&token-hash=hBayGfOmQH3kRMdNnDe4oCZD_9fsJWSt29xXR3KRMVk%3D" alt="Nokotaro Takeda" width="100"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12531784/93a45137841849329ba692da92ac7c60/1.jpeg?token-time=2145916800&token-hash=vGe7wXGqmA8Q7m-kDNb6fyGdwk-Dxk4F-ut8ZZu51RM%3D" alt="Takashi Shibuya" width="100"></td>
</tr><tr>
<td><a href="https://www.patreon.com/mastodon">Gargron</a></td>
<td><a href="https://www.patreon.com/takenoko">Nokotaro Takeda</a></td>
<td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td>
</tr></table>
**Last updated:** Thu, 18 Apr 2019 23:38:06 UTC
**Last updated:** Mon, 13 May 2019 06:13:06 UTC
<!-- PATREON_END -->
:four_leaf_clover: Copyright

View File

@ -61,6 +61,7 @@ common:
month-and-day: "{day}. {month}."
trash: "Koš"
drive: "Disk"
pages: "Stránky"
messaging: "Konverzace"
home: "Domů"
deck: "Deck"
@ -71,12 +72,20 @@ common:
favorites: "Oblíbené"
permissions:
"read:account": "Zobrazit informace o účtu"
"write:account": "Narábět s účtem"
"read:blocks": "Prohlížet blokování"
"write:blocks": "Narábět s blokováním"
"read:drive": "Prohlížet Disk"
"write:drive": "Pracovat s Diskem"
"read:favorites": "Prohlížet oblíbené"
"write:favorites": "Narábět s oblíbeními"
"read:following": "Prohlížet následování"
"write:following": "Pracovat s následováním"
"read:messaging": "Prohlížet konverzaci"
"write:messaging": "Pracovat s konverzaci"
"read:mutes": "Prohlížet ztlumené"
"write:mutes": "Narábět s utíšeními"
"write:notes": "Narábět s poznámkami"
"read:notifications": "Prohlížet oznámení"
"write:notifications": "Pracovat s oznámeními"
"read:reactions": "Prohlížet reakce"
@ -240,7 +249,6 @@ common:
update-available-title: "Aktualizace k dispozici"
update-available: "Je k dispozici nová verze Misskey ({newer},vaše verze je {current}). Pro aplikování nové verze znovunačtěte stránku."
my-token-regenerated: "Váš token byl regenerován, proto budete odhlášen/a."
verified-user: "Ověřené účty"
hide-password: "Skrýt heslo"
show-password: "Zobrazit heslo"
do-not-use-in-production: "Tohle je vývojářský build. Nepoužívejte v produkci."
@ -303,7 +311,6 @@ auth/views/index.vue:
error: "Taková relace neexistuje."
sign-in: "Prosím přihlaste se."
common/views/pages/explore.vue:
verified-users: "Ověřené účty"
popular-users: "Populární uživatelé"
recently-updated-users: "Nedávno aktívni uživatelé"
recently-registered-users: "Nedávno registrovaní uživatelé"
@ -377,6 +384,7 @@ common/views/components/theme.vue:
installed: "\"{}\" byl nainstalován"
create-a-theme: "Vytvořit motiv"
save-created-theme: "Uložit motiv"
text-color: "Barva textu"
base-theme: "Základní vzhled"
base-theme-light: "Světlý"
base-theme-dark: "Tmavý"
@ -454,6 +462,7 @@ common/views/components/user-menu.vue:
suspend: "Zmrazit"
common/views/components/poll.vue:
vote-count: "{} hlasů"
total-votes: "{} hlasů celkem"
vote: "Hlasovat"
show-result: "Podívat se na výsledky"
voted: "Už jste hlasovaly"
@ -464,10 +473,21 @@ common/views/components/poll.vue:
remaining-seconds: "zbývá {s} sekund"
common/views/components/poll-editor.vue:
no-only-one-choice: "Musíte vybrat alespoň dvě možnosti"
choice-n: "Volba {}"
remove: "Odstranit tuto možnost"
add: "+ Přidat možnost"
destroy: "Zahodit dotazník"
expiration: "Termín"
infinite: "Nekonečne"
at: "Výběr data a času"
deadline-date: "Termín ukončení"
interval: "Trvání"
second: "Sekunda"
minute: "Minuta"
hour: "Hodina"
day: "Ne"
common/views/components/reaction-picker.vue:
choose-reaction: "Vyberte svoji reakci"
common/views/components/emoji-picker.vue:
custom-emoji: "Emoji"
people: "Lidé"
@ -902,7 +922,6 @@ admin/views/instance.vue:
invite: "Pozvat"
save: "Uložit"
saved: "Uloženo"
user-recommendation-config: "Doporučení uživatelé"
email: "Emailová adresa"
smtp-port: "SMTP Port"
smtp-auth: "Provést SMTP autentikaci"
@ -954,12 +973,6 @@ admin/views/users.vue:
reset-password: "Resetovat heslo"
reset-password-confirm: "Opravdu chcete resetovat Vaše heslo?"
password-updated: "Heslo je nyní \"{password}\""
verify: "Ověřit účet"
verify-confirm: "Chcete aby toto byl ověřený účet?"
verified: "Účet se nyní ověřuje"
unverify: "Zrušit ověření účtu"
unverify-confirm: "Opravdu chcete zrušit designaci \"ověřený účet\"?"
unverified: "Ruší se potvrzení účtu"
update-remote-user: "Aktualizovat informace o vzdáleném účtu"
users:
title: "Uživatel"
@ -967,7 +980,6 @@ admin/views/users.vue:
all: "Všechny"
moderator: "Moderátor"
adminOrModerator: "Admin/Moderátor"
verified: "Ověřený účet"
origin:
title: "Původ"
combined: "Lokální + Vzdálené"
@ -1032,6 +1044,7 @@ admin/views/federation.vue:
chart-spans:
hour: "za hodinu"
day: "za den"
blocked-hosts: "Blokován"
desktop/views/pages/welcome.vue:
about: "O Misskey"
timeline: "Časová osa"
@ -1198,3 +1211,42 @@ deck/deck.user-column.vue:
activity: "Aktivita"
dev/views/new-app.vue:
app-name-desc: "Jméno vaší aplikace"
pages:
title: "Titulek"
blocks:
post: "Formulář pro psaní"
_post:
text: "Obsah"
_textInput:
text: "Titulek"
_textareaInput:
text: "Titulek"
_numberInput:
text: "Titulek"
_switch:
text: "Titulek"
_counter:
text: "Titulek"
_button:
text: "Titulek"
_action:
_dialog:
content: "Obsah"
script:
categories:
random: "Náhodně"
list: "Seznamy"
blocks:
_join:
arg1: "Seznamy"
random: "Náhodně"
_randomPick:
arg1: "Seznamy"
_dailyRandomPick:
arg1: "Seznamy"
_seedRandomPick:
arg2: "Seznamy"
_pick:
arg1: "Seznamy"
types:
array: "Seznamy"

View File

@ -53,6 +53,7 @@ common:
month-and-day: "{day}/{month}"
trash: "Papierkorb"
drive: "Drive"
pages: "Seite"
messaging: "Unterhaltungen"
home: "Home"
deck: "Stapel"
@ -64,6 +65,7 @@ common:
permissions:
"read:account": "Accountinformationen anzeigen."
"write:account": "Accountinformationen bearbeiten."
"read:blocks": "Blöcke anzeigen"
"read:drive": "Dateien anzeigen"
"write:drive": "Dateien bearbeiten"
"read:favorites": "Favoriten anzeigen"
@ -151,7 +153,6 @@ common:
update-available-title: "Aktualisierung verfügbar"
update-available: "Eine neue Version von Misskey ist verfügbar ({newer}, aktuell ist {current}). Lade die Seite neu um die aktuelle Version zu laden"
my-token-regenerated: "Dein Token wurde generiert. Du wirst jetzt abgemeldet."
verified-user: "Verifizierter Benutzer"
do-not-use-in-production: "Dies ist eine Entwicklungsversion. Nicht in einer Produktivumgebung verwenden."
error:
retry: "Erneut versuchen"
@ -197,8 +198,6 @@ auth/views/index.vue:
please-go-back: "Bitte gehe zurück zur Anwendung."
error: "Sitzung ist nicht vorhanden."
sign-in: "Bitte melde dich an."
common/views/pages/explore.vue:
verified-users: "Verifizierter Benutzer"
common/views/components/games/reversi/reversi.vue:
matching:
waiting-for: "Warten auf {}"
@ -603,8 +602,6 @@ admin/views/drive.vue:
delete: "Löschen"
admin/views/users.vue:
users:
state:
verified: "Verifizierter Benutzer"
origin:
local: "Lokal"
admin/views/emoji.vue:
@ -718,25 +715,6 @@ deck/deck.user-column.vue:
docs:
edit-this-page-on-github: "Hast Du einen Fehler gefunden oder Lust, diese Dokumentation zu verbessern?"
edit-this-page-on-github-link: "Seite auf GitHub bearbeiten!"
api:
entities:
properties: "Eigenschaften"
endpoints:
params: "Parameter"
no-params: "Keine Parameter."
res: "Antwort"
require-credential: "Dieser Endpunkt erfordert eine Authentifizierung."
require-permission: "Dieser Endpunkt erfordert die {permission} Berechtigung."
has-limit: "Es gibt eine Ratenbegrenzung."
duration-limit: "Es sind maximal {max} Anfragen pro {duration} Millisekunden möglich."
min-interval-limit: "Es ist nur eine Anfrage alle {interval} Millisekunden möglich."
show-src: "Quellcode anzeigen."
show-src-link: "Quellcode auf GitHub anzeigen"
generated: "Dieses Dokument wird automatisch anhand der API-Definition generiert."
props:
name: "Name"
type: "Typ"
description: "Beschreibung"
dev/views/index.vue:
manage-apps: "Anwendungen verwalten"
dev/views/apps.vue:
@ -753,3 +731,24 @@ dev/views/new-app.vue:
authority: "Berechtigungen"
authority-desc: "Nur die hier eingetragenen Berechtigungen, werden per API zur Verfügung stehen."
authority-warning: "Dies kann auch nach dem erstellen der Anwendung geändert werden, allerdings werden dann alle bisher generierten Token ungültig."
pages:
blocks:
post: "\"Neuer Beitrag\"-Formular"
script:
categories:
random: "Zufällige Auswahl"
list: "Listen"
blocks:
_join:
arg1: "Listen"
random: "Zufällige Auswahl"
_randomPick:
arg1: "Listen"
_dailyRandomPick:
arg1: "Listen"
_seedRandomPick:
arg2: "Listen"
_pick:
arg1: "Listen"
types:
array: "Listen"

View File

@ -34,6 +34,7 @@ common:
signup: "Sign up"
signout: "Logout"
reload-to-apply-the-setting: "You'll need to reload the page to reflect this setting. Do you want to reload it now?"
fetching-as-ap-object: "Inquiring to union"
got-it: "Got it!"
customization-tips:
title: "Customization tips"
@ -61,6 +62,7 @@ common:
month-and-day: "{month}/{day}"
trash: "Trash"
drive: "Drive"
pages: "Pages"
messaging: "Talk"
home: "Home"
deck: "Deck"
@ -249,7 +251,6 @@ common:
update-available-title: "Update available"
update-available: "A new version of Misskey is now available({newer}, the current version is {current}). Reload the page to apply updates."
my-token-regenerated: "Your token has been regenerated, so you will be signed out."
verified-user: "Verified account"
hide-password: "Hide Password"
show-password: "Show Password"
do-not-use-in-production: "This is a development build. Do not use in production."
@ -317,7 +318,7 @@ auth/views/index.vue:
error: "Session does not exist."
sign-in: "Please sign in."
common/views/pages/explore.vue:
verified-users: "Official accounts"
pinned-users: "Higlighted users"
popular-users: "Popular users"
recently-updated-users: "Recently active users"
recently-registered-users: "Users who joined recently"
@ -1137,7 +1138,7 @@ admin/views/instance.vue:
invite: "Invite"
save: "Save"
saved: "Saved"
user-recommendation-config: "Recommended users"
pinned-users: "Higlighted user"
email-config: "Email server settings"
email-config-info: "Used to confirm email and password reset etc."
enable-email: "Enable email delivery"
@ -1221,12 +1222,6 @@ admin/views/users.vue:
silence-confirm: "Silence user?"
unmake-silence: "Unsilence"
unsilence-confirm: "Are you certain that you want to stop silencing this user?"
verify: "Verify account"
verify-confirm: "Do you want this to be a verified account?"
verified: "The account is now being verified"
unverify: "Unverify account"
unverify-confirm: "Do you want to remove the 'verified account' designation?"
unverified: "The account is now being unverified"
update-remote-user: "Update information about remote user"
remote-user-updated: "The information regarding the remote user has been updated."
users:
@ -1243,7 +1238,6 @@ admin/views/users.vue:
admin: "Administrator"
moderator: "Moderator"
adminOrModerator: "Admin/Moderator"
verified: "Verified account"
silenced: "Already silenced"
suspended: "Suspended"
origin:
@ -1351,6 +1345,7 @@ admin/views/federation.vue:
chart-spans:
hour: "Hourly"
day: "Daily"
blocked-hosts: "Blocking"
desktop/views/pages/welcome.vue:
about: "More details..."
timeline: "Timeline"
@ -1621,25 +1616,6 @@ deck/deck.user-column.vue:
docs:
edit-this-page-on-github: "Found an error, or do you want to contribute to the documentation?"
edit-this-page-on-github-link: "Edit this page at GitHub!"
api:
entities:
properties: "Properties"
endpoints:
params: "Parameters"
no-params: "No parameter."
res: "Response"
require-credential: "This endpoint requires the authentication information."
require-permission: "This endpoint requires {permission} permission."
has-limit: "There is a rate limit."
duration-limit: "If you have sent your requests more than {max} times in {duration} milliseconds, you will be unable to send more requests."
min-interval-limit: "If {interval} milliseconds haven't passed since the last request, you can't send a request."
show-src: "You can view the source code for this endpoint."
show-src-link: "See the code on GitHub"
generated: "This document is generated by the API definition."
props:
name: "Name"
type: "Type"
description: "Description"
dev/views/index.vue:
manage-apps: "Manage apps"
dev/views/apps.vue:
@ -1648,13 +1624,252 @@ dev/views/apps.vue:
app-missing: "No apps"
dev/views/new-app.vue:
new-app: "New Application"
new-app-info: "You can also create an application with the API. (app/create)"
create-app: "Creating application"
app-name: "Application name"
app-name-placeholder: "ex) Misskey for iOS"
app-name-desc: "The name of your app"
app-overview: "Application summary"
app-overview-placeholder: " ex) Misskey iOS Client."
app-overview-desc: "A brief description, or an introduction of your app."
callback-url: "The callback URL (optional)"
callback-url-placeholder: "ex) https://your.app.example.com/callback.php"
callback-url-desc: "The URL to redirect to after the user is authenticated via the authentication form."
authority: "Permissions"
authority-desc: "Only the functions requested here can be accessed via the API."
authority-warning: "You can change it even after creating the application, but if you give different permissions, all user keys associated at that time will be invalidated."
pages:
new-page: "Create a page"
edit-page: "Edit a page"
read-page: "Viewing the source"
page-created: "Created the page!"
page-updated: "Updated the page"
are-you-sure-delete: "Do you want to delete this page?"
page-deleted: "The page has been deleted"
edit-this-page: "Edit this page"
view-source: "View Source"
view-page: "View page"
inspector: "Inspector"
content: "Page block"
variables: "Variables"
more-details: "Description"
title: "Title"
url: "Page URL"
summary: "Summary of page"
align-center: "Center align"
font: "Font"
fontSerif: "Serif"
fontSansSerif: "Sans Serif"
set-eye-catching-image: "Set an eye-catching image"
remove-eye-catching-image: "Delete an eye-catching image"
choose-block: "Add a block"
select-type: "Select a type"
enter-variable-name: "Please choose a variable name"
the-variable-name-is-already-used: "This variable name is already used"
content-blocks: "Content"
input-blocks: "Input"
special-blocks: "Special"
post-from-post-form: "Post this content"
posted-from-post-form: "Posted!"
blocks:
text: "Text"
textarea: "Text area"
section: "Section"
image: "Images"
button: "Button"
if: "If"
_if:
variable: "Variables"
post: "Post form"
_post:
text: "Content"
textInput: "Text input"
_textInput:
name: "Variable name"
text: "Title"
default: "Default value"
textareaInput: "Multiple type text input"
_textareaInput:
name: "Variable name"
text: "Title"
default: "Default value"
numberInput: "Numeric input"
_numberInput:
name: "Variable name"
text: "Title"
default: "Default value"
switch: "Switch"
_switch:
name: "Variable name"
text: "Title"
default: "Default value"
counter: "Counter"
_counter:
name: "Variable name"
text: "Title"
inc: "Increase number"
_button:
text: "Title"
action: "Operation when the button pressed"
_action:
dialog: "Show a dialog"
_dialog:
content: "Content"
resetRandom: "Reset a random number"
script:
categories:
flow: "Control"
logical: "Logical operation"
operation: "Compute"
comparison: "Compare"
random: "Random"
value: "Value"
fn: "Function"
text: "Text operation"
convert: "Variable"
list: "Lists"
blocks:
text: "Text"
multiLineText: "Text (Multiple lines)"
textList: "List of text"
_textList:
info: "Separate each one with a newline"
strLen: "Length of text"
_strLen:
arg1: "Text"
strPick: "Extract character"
_strPick:
arg1: "Text"
arg2: "Position of character"
strReplace: "Replace string(s)"
_strReplace:
arg1: "Text"
arg2: "Before replacement"
arg3: "After replacement"
strReverse: "Flip text"
_strReverse:
arg1: "Text"
_join:
arg1: "Lists"
arg2: "Separator"
add: "+ Plus"
_add:
arg1: "A"
arg2: "B"
subtract: "- Minus"
_subtract:
arg1: "A"
arg2: "B"
multiply: "× Multiply"
_multiply:
arg1: "A"
arg2: "B"
divide: "÷ Divide"
_divide:
arg1: "A"
arg2: "B"
_remind:
arg1: "A"
arg2: "B"
eq: "A and B are equal"
_eq:
arg1: "A"
arg2: "B"
notEq: "A and B are different"
_notEq:
arg1: "A"
arg2: "B"
and: "A and B"
_and:
arg1: "A"
arg2: "B"
or: "A or B"
_or:
arg1: "A"
arg2: "B"
lt: "A is smaller than B"
_lt:
arg1: "A"
arg2: "B"
gt: "A is bigger than B"
_gt:
arg1: "A"
arg2: "B"
ltEq: "A is smaller or same than B"
_ltEq:
arg1: "A"
arg2: "B"
gtEq: "A is bigger or same than B"
_gtEq:
arg1: "A"
arg2: "B"
if: "Branch"
_if:
arg1: "If"
arg2: "then"
arg3: "else"
not: "denial"
_not:
arg1: "denial"
random: "Random"
_random:
arg1: "Probability"
rannum: "Random number"
_rannum:
arg1: "Minimum"
arg2: "Maximum"
randomPick: "Choose at random from the list"
_randomPick:
arg1: "Lists"
dailyRandom: "Random (Daily for each user)"
_dailyRandom:
arg1: "Probability"
dailyRannum: "Random number (Daily for each user)"
_dailyRannum:
arg1: "Minimum"
arg2: "Maximum"
dailyRandomPick: "Choose at random from the list (Daily for each user)"
_dailyRandomPick:
arg1: "Lists"
_seedRandom:
arg1: "Seed"
arg2: "Probability"
_seedRannum:
arg1: "Seed"
arg2: "Minimum"
arg3: "Maximum"
_seedRandomPick:
arg1: "Seed"
arg2: "Lists"
_DRPWPM:
arg1: "List of text"
_pick:
arg1: "Lists"
arg2: "Position"
number: "Number"
stringToNumber: "Text to number"
_stringToNumber:
arg1: "Text"
numberToString: "Number to text"
_numberToString:
arg1: "Number"
splitStrByLine: "Split the text by lines"
_splitStrByLine:
arg1: "Text"
ref: "Variables"
fn: "Function"
_fn:
slots: "Slots"
arg1: "Output"
for: "Repeat"
thereIsEmptySlot: "Slot {slot} is empty!"
types:
string: "Text"
number: "Number"
boolean: "Flag"
array: "Lists"
stringArray: "List of text"
emptySlot: "Empty slot"
enviromentVariables: "Environment variable"
pageVariables: "Page element"
argVariables: "Input slot"

View File

@ -12,7 +12,9 @@ common:
rich-contents: "Posts"
rich-contents-desc: "Escribe sobre tus pensamientos, eventos, todo lo que quieras compartir. Si es necesario, puedes usar varias sintaxis, decorar tus posts y añadir tus imágenes favoritas, archivos de viddeo y encuestas."
reaction: "Reacciones"
reaction-desc: "La forma mas facil de expresar tus emociones. Misskey te permite añadir varios tipos de reacciones a los posts de otros usuarios. La emperiencia emocional en Misskey nunca será igual que en otra red social, donde solo puedes poner \"likes\"."
ui: "Interfaz"
ui-desc: "No hay ninguna interfaz que le vaya bien a todos. Por eso, Misskey tiene una interfaz altamente personalizable para tus gustos. Puedes hacer tu página principal única editando la interfaz de tu timeline y moviendo varios widgets para conseguir hacer de este lugar uno propio."
drive: "Drive"
adblock:
detected: "Por favor, desactive el bloqueador de publicidad."
@ -55,6 +57,7 @@ common:
month-and-day: "{day} de {month}"
trash: "Papelera"
drive: "Drive"
pages: "Páginas"
messaging: "Conversación"
home: "Inicio"
deck: "Deck"
@ -70,8 +73,12 @@ common:
"write:blocks": "Editar bloques"
"read:favorites": "Ver favoritos"
"write:favorites": "Editar favoritos"
"read:following": "Ver información de seguidor"
"read:messaging": "Ver conversación"
"read:mutes": "Ver silenciados"
"write:notes": "Crear y eliminar articulos"
"read:notifications": "Ver notificaciones"
"read:reactions": "Ver reacciones"
"write:votes": "Vota"
weekday-short:
sunday: "domingo"
@ -136,8 +143,11 @@ common:
default-note-visibility: "Rango de publicación predeterminado"
web-search-engine: "Buscador web"
web-search-engine-desc: "Ejemplo: https://www.google.com/?#q={{query}}"
this-setting-is-this-device-only: "Solo para este dispositivo"
use-os-default-emojis: "Usar los emoticonos estándar del sistema operativo"
line-width: "Grosor de línea"
line-width-thin: "Fino"
line-width-normal: "Normal"
line-width-thick: "Grosor"
font-size: "Tamaño del texto"
font-size-x-small: "Muy pequeño"
@ -162,13 +172,20 @@ common:
wallpaper: "Fondo de pantalla"
choose-wallpaper: "Escoge un fondo de pantalla"
delete-wallpaper: "Quitar fondo de pantalla"
post-form-on-timeline: "Mostrar el formulario de las entradas encima de la línea de tiempo"
show-clock-on-header: "Muestra el reloj en la parte superior derecha"
show-reply-target: "Mostrar destinatario de la mención"
timeline: "Timeline"
show-my-renotes: "Mostrar mis renotes en la timeline"
show-renoted-my-notes: "Mostrar renotes de mis posts en la timeline"
sound: "Sonido"
enable-sounds: "Habilitar sonido"
volume: "Volúmen"
test: "Prueba"
update: "Actualizar Misskey"
version: "Versión"
latest-version: "Última versión"
update-checking: "Buscando actualizaciones"
no-updates: "No hay actualizaciones disponibles"
no-updates-desc: "Tu Misskey está actualizado"
update-available: "¡Una nueva versión está disponible!"
@ -178,18 +195,36 @@ common:
search: "Buscar"
delete: "eliminar"
loading: "cargando"
ok: "Confirmar"
cancel: "Cancelar"
update-available-title: "Actualización disponible"
update-available: "Hay disponible una nueva versión de Misskey ({newer}, la versión actual es {current}). Refresca la página para aplicar las actualizaciones."
my-token-regenerated: "Tu token se ha regenerado vas a ser desconectado."
verified-user: "Cuenta verificada"
hide-password: "Ocultar contraseña"
show-password: "Mostrar contraseña"
do-not-use-in-production: "Esto está en desarrollo, no usarlo para producción."
user-suspended: "Este usuario ha sido suspendido"
is-remote-user: "La información sobre este usuario puede no estar completa"
is-remote-post: "Es una publicación remota"
view-on-remote: "Consultar el perfil completo"
renoted-by: "Renotado por {user}"
no-notes: "No hay publicaciones"
turn-on-darkmode: "Cambiar a modo oscuro"
turn-off-darkmode: "Modo claro"
error:
title: "Se ha producido un problema :("
retry: "Inténtalo otra vez"
reversi:
drawn: "Empatado"
my-turn: "Mi turno"
opponent-turn: "Turno del oponente"
turn-of: "Turno de {name}"
past-turn-of: "Turno de {name}"
won: "{name} ha ganado"
black: "Negro"
white: "Blanco"
total: "Total"
this-turn: "Turno {count}"
widgets:
analog-clock: "Reloj analógico"
profile: "Perfil"
@ -212,8 +247,12 @@ common:
nav: "Navegación"
tips: "Consejos"
hashtags: "Etiquetas"
queue: "En cola"
dev: "Se ha producido un error creando la aplicación. Intentelo de nuevo."
ai-chan-kawaii: "Ai-chan es muy mona!"
you: "Tú"
auth/views/form.vue:
share-access: "¿Deseas permitir a <i>{name}</i> acceder a tu cuenta?"
permission-ask: "La aplicación requiere los siguientes permisos:"
cancel: "Cancelar"
accept: "Garantizar acceso."
@ -228,7 +267,18 @@ auth/views/index.vue:
error: "Esta sesión no existe."
sign-in: "Por favor inicia sesión."
common/views/pages/explore.vue:
verified-users: "Cuenta verificada"
popular-users: "Usuarios populares"
recently-updated-users: "Usuarios activos recientemente"
recently-registered-users: "Usuarios que se han unido recientemente"
popular-tags: "Etiquetas populares"
federated: "Desde el fediverso"
explore: "Explorar {host}"
users-info: "Actualmente hay {users} registrados aquí"
common/views/components/url-preview.vue:
enable-player: "Activar reproducción"
disable-player: "Cerrar el reproductor"
common/views/components/user-list.vue:
no-users: "No hay usuarios."
common/views/components/games/reversi/reversi.vue:
matching:
waiting-for: "Esperando por {}"
@ -244,6 +294,7 @@ common/views/components/games/reversi/reversi.index.vue:
sub-title: "¡Juega Reversi con tus amigos!"
invite: "Invitar"
rule: "Cómo jugar"
rule-desc: "Reversi es un juego de estrategia para dos jugadores, el cual se juega en un tablero de 8x8. Hay 64 fichas llamadas discos, las cuales son claras de un lado y oscuras del otro. Los jugadores toman turnos colocando fichas en el tablero con su color asignado mirando hacia arriba. Durante una jugada, cualquier disco del color del oponente que esté en fila entre un disco del oponente y otro del mismo color, será volteado para tener el color del jugador que haya hecho la movida. El objetivo del juego es tener la mayoría de los discos de tu color cuando el último cuadro es llenado."
mode-invite: "Invitar"
mode-invite-desc: "Invitar un usuario al juego."
invitations: "¡Has recibido una invitación!"
@ -300,23 +351,40 @@ common/views/components/media-banner.vue:
click-to-show: "Click para mostrar"
common/views/components/theme.vue:
theme: "Tema"
light-theme: "Tema a usar en Light mode"
dark-theme: "Tema a usar en dark mode"
light-themes: "Tema claro"
dark-themes: "Tema oscuro"
install-a-theme: "Instalar tema"
theme-code: "Código del tema"
install: "Instalación"
installed: "\"{}\" se ha instalado"
create-a-theme: "Crear tema"
save-created-theme: "Guardar tema"
primary-color: "Color primario"
secondary-color: "Color secundario"
text-color: "Color del texto"
base-theme: "Tema base"
base-theme-light: "Claro"
base-theme-dark: "Oscuro"
find-more-theme: "Obtener más temas"
theme-name: "Nombre del tema"
preview-created-theme: "Vista previa"
invalid-theme: "No es un tema válido"
already-installed: "Este tema ya está instalado."
saved: "Guardado"
manage-themes: "Gestor de temas"
builtin-themes: "Temas estandar"
my-themes: "Mis temas"
installed-themes: "Temas instalados"
select-theme: "Elegir tema"
uninstall: "Desinstalar"
uninstalled: "\"{}\" ha sido desinstalado"
author: "Autor"
desc: "Descripción"
export: "Exportar"
import: "Importar"
import-by-code: "o pega el código"
common/views/components/cw-button.vue:
show: "Mostrar"
chars: "{count} letras"
@ -430,10 +498,25 @@ common/views/components/stream-indicator.vue:
connected: "Conectado"
common/views/components/notification-settings.vue:
title: "Notificaciones"
common/views/components/integration-settings.vue:
title: "Integraciones"
connect: "Conectar"
disconnect: "Desconectarse"
connected-to: "Estas conectado a la siguiente cuenta"
common/views/components/github-setting.vue:
description: "Una vez conectada tu cuenta de GitHub a Misskey podrás ver la información sobre tu perfil de GitHub y además podrás registrarte mediante tu cuenta de GitHub."
connected-to: "Estas conectado a esta cuenta de GitHub"
detail: "Ver detalles..."
reconnect: "Reconectar"
connect: "Vincular tu cuenta de GitHub"
disconnect: "Desconectarse"
common/views/components/discord-setting.vue:
description: "Una vez conectada tu cuenta de Discord a Misskey podrás ver la información sobre tu perfil de Discord y además podrás registrarte mediante tu cuenta de Discord."
connected-to: "Estas conectado a esta cuenta de Discord"
detail: "Ver detalles..."
reconnect: "Reconectar"
connect: "Vincular tu cuenta de Discord"
disconnect: "Desconectarse"
common/views/components/uploader.vue:
waiting: "Un momento"
common/views/components/visibility-chooser.vue:
@ -445,27 +528,65 @@ common/views/components/visibility-chooser.vue:
specified: "Directo"
specified-desc: "Publica solo para los seguidores que quieras"
local-public: "Público (sólo local)"
local-public-desc: "No publicar para remoto"
local-home: "Inicio (sólo local)"
local-followers: "Seguidores (sólo local)"
common/views/components/trends.vue:
count: "{} usuarios mencionados"
empty: "Ninguna tendencia popular ahora"
common/views/components/language-settings.vue:
title: "Mostrar idioma"
pick-language: "Selecciona un idioma"
recommended: "Recomendado"
auto: "Automático"
specify-language: "Especifica el idioma"
info: "Necesitas recargar la página para que los cambios tengan efecto."
common/views/components/profile-editor.vue:
title: "Perfil"
name: "Nombre"
account: "Cuenta"
location: "Localización"
description: "Acerca de mí"
you-can-include-hashtags: "También puedes incluir hashtags en la descripción de tu perfil."
language: "Idioma"
birthday: "Fecha de nacimiento"
avatar: "Avatar"
banner: "Banner"
is-cat: "Esta cuenta es un gato"
is-bot: "Esta cuenta es un bot"
is-locked: "Las peticiones de seguimiento necesitan aprobación"
careful-bot: "Las peticiones de seguimiento de bots necesitan aprobación"
auto-accept-followed: "Aprobar automaticamente las peticiones de follow de gente a la que sigues"
advanced: "Otros"
privacy: "Privacidad"
save: "Guardar"
saved: "Perfil actualizado con exito"
uploading: "Subiendo"
upload-failed: "Error al subir"
email: "Preferencias de correo"
email-address: "Correo electrónico"
email-verified: "Tu cuenta de correo ha sido verificada."
email-not-verified: "Tu cuenta de correo no está verificada. Por favor comprueba tu bandeja de entrada."
export: "Exportar"
import: "Importar"
export-and-import: "Exportar/Importar"
export-targets:
all-notes: "Todas las notas publicadas"
following-list: "Seguidores"
mute-list: "Silenciar"
blocking-list: "Bloquear"
user-lists: "Listas"
export-requested: "Has solicitado una exportación. Esto puede tardar un rato. Después de que termine la exportación el archivo se añadirá al drive."
import-requested: "Has empezado una importación. Esto puede tardar un rato."
enter-password: "Escribe una contraseña"
danger-zone: "Zona de peligro"
delete-account: "Eliminar cuenta"
account-deleted: "Esta cuenta ha sido eliminada. Puede tardar un rato hasta que toda la información desaparazca."
common/views/components/user-list-editor.vue:
users: "Usuarios"
rename: "Cambiar el nombre de la lista"
delete: "Eliminar lista"
remove-user: "Eliminar de la lista"
common/views/components/user-lists.vue:
list-name: "Nombre de lista"
common/views/widgets/broadcast.vue:
@ -788,24 +909,46 @@ admin/views/index.vue:
instance: "Instancia"
moderators: "Moderadores"
users: "Usuarios"
federation: "Federado"
hashtags: "Hashtags"
queue: "Cola de trabajos"
logs: "Registros"
back-to-misskey: "Volver a Misskey"
admin/views/dashboard.vue:
dashboard: "Panel de Control"
accounts: "Cuenta"
notes: "Publicaciones"
drive: "Drive"
instances: "Instancias"
this-instance: "Esta instancia"
federated: "Federado"
admin/views/queue.vue:
title: "Cola"
remove-all-jobs: "Limpiar todos los trabajos pendientes"
admin/views/abuse.vue:
title: "Abuso"
target: "Destinatario"
reporter: "Informador"
details: "Detalles"
remove-report: "eliminar"
admin/views/instance.vue:
instance: "Instancia"
instance-name: "Nombre de la instancia"
instance-description: "Descripción de la instancia"
host: "Host"
banner-url: "URL de la imagen de banner"
error-image-url: "Error en la URL de la imagen"
languages: "Idioma de esta instancia"
languages-desc: "Puedes añadir mas de uno, separado por espacios."
maintainer-config: "Información del administrador"
maintainer-name: "Nombre del administrador"
maintainer-email: "Contactar con el administrador"
drive-config: "Ajustes del Drive"
cache-remote-files: "Mantener en cache los archivos remotos"
recaptcha-secret-key: "clave secreta reCAPTCHA"
invite: "Invitar"
save: "Guardar"
saved: "Guardado"
email: "Correo electrónico"
smtp-host: "Host SMTP"
smtp-port: "Puerto SMTP"
@ -834,7 +977,6 @@ admin/views/users.vue:
state:
all: "Todo"
moderator: "Moderadores"
verified: "Cuenta verificada"
origin:
local: "Local"
admin/views/emoji.vue:
@ -846,12 +988,14 @@ admin/views/announcements.vue:
save: "Guardar"
remove: "eliminar"
add: "Agregar"
saved: "Guardado"
admin/views/federation.vue:
instance: "Instancia"
host: "Host"
following: "Siguiendo"
status: "Estado"
block: "Bloquear"
instances: "Federado"
states:
all: "Todo"
blocked: "Bloquear"
@ -859,6 +1003,7 @@ admin/views/federation.vue:
chart-spans:
hour: "Por hora"
day: "Por día"
blocked-hosts: "Bloquear"
desktop/views/pages/selectdrive.vue:
cancel: "Cancelar"
desktop/views/pages/user-list.users.vue:
@ -969,3 +1114,24 @@ deck:
rename: "Renombrar"
deck/deck.user-column.vue:
activity: "Actividad"
pages:
blocks:
post: "Formulario"
script:
categories:
random: "Aleatorio"
list: "Listas"
blocks:
_join:
arg1: "Listas"
random: "Aleatorio"
_randomPick:
arg1: "Listas"
_dailyRandomPick:
arg1: "Listas"
_seedRandomPick:
arg2: "Listas"
_pick:
arg1: "Listas"
types:
array: "Listas"

View File

@ -13,7 +13,7 @@ common:
rich-contents-desc: "Partagez vos idées, les événements et les sujets qui vous tiennent à cœur ainsi que tout autre chose que vous souhaitez partager avec les autres. Si vous le désirez, vous pouvez décorer vos messages en utilisant une syntaxe différente ou en y joignant des sondages et des fichiers, tels que les photos ou les vidéos que vous aimez."
reaction: "Réactions"
reaction-desc: "Une manière simple d'exprimer vos émotions. Misskey peut attacher diverses réactions aux publications des autres utilisateurs. Si vous essayez les réactions sur Misskey, vous ne pourrez plus retourner sur une autre plateforme de réseaux sociaux n'offrant que des « J'aime »."
ui: "Interface utilisateur"
ui: "Interface"
ui-desc: "Aucune interface graphique ne peut plaire à tout le monde. Par conséquent, Misskey possède une interface utilisateur hautement personnalisable selon vos goûts. Vous pouvez rendre votre page d'accueil originale en modifiant la mise en page de votre fil et en déplaçant les widgets que vous pouvez facilement ajuster pour vous approprier cet espace."
drive: "Drive"
drive-desc: "Vous voulez poster une photo que vous avez déjà transférée ? Vous souhaitez organiser, nommer et créer un dossier pour vos fichiers téléversés ? Misskey Drive est la meilleure solution pour vous. Très facile de partager vos fichiers en ligne."
@ -33,6 +33,7 @@ common:
signin: "Se connecter"
signup: "S'enregistrer"
signout: "Se déconnecter"
reload-to-apply-the-setting: "Le rechargement de la page est nécessaire pour appliquer ces paramètres. Désirez-vous la recharger maintenant ?"
got-it: "Jai compris !"
customization-tips:
title: "Conseils de personnalisation"
@ -59,6 +60,7 @@ common:
month-and-day: "{day}-{month}"
trash: "Corbeille"
drive: "Drive"
pages: "Pages"
messaging: "Conversations"
home: "Principal"
deck: "Deck"
@ -70,10 +72,18 @@ common:
permissions:
"read:account": "Afficher les informations du compte"
"write:account": "Mettre à jour les informations de votre compte"
"read:blocks": "Voir les blocs"
"write:blocks": "Écrire des blocs"
"read:drive": "Parcourir le Drive"
"write:drive": "Écrire sur le Drive"
"read:favorites": "Afficher les favoris"
"write:favorites": "Écrire des favoris"
"write:messaging": "Utiliser la messagerie"
"write:notes": "Créer ou supprimer des publications"
"read:notifications": "Afficher les notifications"
"write:notifications": "Gérer vos notifications"
"read:reactions": "Lire les réactions"
"write:reactions": "Gérer vos réactions"
"write:votes": "Vote"
empty-timeline-info:
follow-users-to-make-your-timeline: "Les utilisateurs suivants afficheront leurs publications sur votre fil."
@ -129,7 +139,7 @@ common:
notification: "Notifications"
apps: "Applications"
tags: "Hashtags"
mute-and-block: "Silencer / Bloquer"
mute-and-block: "Silencés / Bloqués"
blocking: "En cours blocage"
security: "Sécurité"
signin: "Historique des connexions"
@ -189,6 +199,7 @@ common:
show-clock-on-header: "Afficher l'horloge sur le coté supérieur droit"
timeline: "Fil dactualité"
show-my-renotes: "Afficher mes republications dans le fil"
show-renoted-my-notes: "Afficher les partages de mes propres notes sur le fil"
remain-deleted-note: "Continuer à afficher les notes supprimées"
sound: "Son"
enable-sounds: "Activer les sons"
@ -209,16 +220,16 @@ common:
debug-mode: "Activer le mode débogage"
debug-mode-desc: "Ce paramètre est stocké dans le navigateur."
navbar-position: "Position de la barre de navigation"
navbar-position-top: "en haut"
navbar-position-top: "En haut"
navbar-position-left: "À gauche"
navbar-position-right: "à droite"
navbar-position-right: "À droite"
i-am-under-limited-internet: "J'ai un accès Internet limité"
post-style: "Style d'affichage des notes"
post-style-standard: "Standard"
post-style-smart: "Intelligent"
notification-position: "Afficher les notifications"
notification-position-bottom: "en bas"
notification-position-top: "en haut"
notification-position-top: "En haut"
disable-via-mobile: "Enlever la mention publié via 'mobile'"
load-raw-images: "Afficher les photos jointes dans leur qualité originale"
load-remote-media: "Afficher les médias depuis le serveur distant"
@ -230,7 +241,6 @@ common:
update-available-title: "Mise à jour disponible"
update-available: "Une nouvelle version de Misskey est disponible ({newer}, version actuelle: {current}). Veuillez recharger la page pour appliquer la mise à jour."
my-token-regenerated: "Votre jeton vient dêtre généré, vous allez maintenant être déconnecté."
verified-user: "Compte vérifié"
hide-password: "Masquer le mot de passe"
show-password: "Afficher le mot de passe"
do-not-use-in-production: "Il sagit dune version de développement. Ne pas utiliser dans un environnement de production."
@ -298,7 +308,6 @@ auth/views/index.vue:
error: "La session nexiste pas."
sign-in: "Veuillez vous connecter"
common/views/pages/explore.vue:
verified-users: "Comptes vérifiés"
popular-users: "Utilisateurs populaires"
recently-updated-users: "Utilisateurs actifs récemment"
recently-registered-users: "Les nouveaux inscrits"
@ -307,6 +316,7 @@ common/views/pages/explore.vue:
explore: "Explorer {host}"
users-info: "Actuellement, {users} utilisateurs se sont inscrit ici"
common/views/components/url-preview.vue:
enable-player: "Activer la lecture"
disable-player: "Fermer le lecteur"
common/views/components/user-list.vue:
no-users: "Il n'y a aucun utilisateur"
@ -450,6 +460,7 @@ common/views/components/nav.vue:
repository: "Dépôt"
develop: "Développeurs"
feedback: "Suggestions"
tos: "Conditions d'utilisation"
common/views/components/note-menu.vue:
mention: "Mention"
detail: "Détails"
@ -468,8 +479,12 @@ common/views/components/user-menu.vue:
mention: "Mention"
mute: "Silencier"
unmute: "Enlever la sourdine"
mute-confirm: "Rendre muet cet utilisateur ?"
unmute-confirm: "Ne plus masquer cet utilisateur ?"
block: "Bloquer"
unblock: "Débloquer"
block-confirm: "Bloquer cet utilisateur ?"
unblock-confirm: "Débloquer cet utilisateur ?"
push-to-list: "Ajouter à une liste"
select-list: "Sélectionnez une liste"
report-abuse: "Signaler un abus"
@ -552,6 +567,7 @@ common/views/components/signup.vue:
password-matched: "OK"
password-not-matched: "Les mots de passe ne correspondent pas."
recaptcha: "Vérifier"
tos: "Conditions d'utilisation"
create: "Créer un compte"
some-error: "La création du compte a échoué. Veuillez réessayer."
common/views/components/special-message.vue:
@ -647,6 +663,7 @@ common/views/components/profile-editor.vue:
blocking-list: "Liste des comptes bloqués"
user-lists: "Listes"
export-requested: "Vous avez demandé une exportation. Cela peut prendre un certain temps. Une fois l'exportation terminée, le fichier résultant sera ajouté dans le Drive."
import-requested: "Vous avez initié un import. Ceci peut prendre un peu de temps."
enter-password: "Veuillez saisir votre mot de passe"
danger-zone: "Zone de danger"
delete-account: "Supprimer le compte"
@ -659,6 +676,7 @@ common/views/components/user-list-editor.vue:
delete-are-you-sure: "Voulez-vous vraiment supprimer la liste « $1 » ?"
deleted: "Supprimé"
common/views/components/user-lists.vue:
create-list: "Créer une liste"
list-name: "Nom de la liste"
common/views/widgets/broadcast.vue:
fetching: "Récupération"
@ -1099,7 +1117,6 @@ admin/views/instance.vue:
invite: "Inviter"
save: "Sauvegarder"
saved: "Enregistré"
user-recommendation-config: "Utilisateurs"
email-config: "Paramètres du serveur de messagerie"
email-config-info: "Utilisé pour confirmer votre adresse de courrier électronique et la réinitialisation de votre mot de passe."
enable-email: "Activation de la distribution du courrier"
@ -1180,13 +1197,8 @@ admin/views/users.vue:
unsuspend-confirm: "Souhaiteriez-vous ne plus suspendre ce compte ?"
unsuspended: "La suspension de lutilisateur a été levée avec succès"
make-silence: "Mettre en sourdine"
silence-confirm: "Mettre l'utilisateur sous silence ?"
unmake-silence: "Enlever la sourdine"
verify: "Vérification du compte"
verify-confirm: "Souhaiteriez-vous rendre votre compte comme étant un compte vérifié ?"
verified: "Le compte a été vérifié"
unverify: "Enlever la vérification du compte"
unverify-confirm: "Désirez-vous considérer ce compte comme étant non-vérifié ?"
unverified: "Ce compte n'est plus vérifié"
update-remote-user: "Mettre à jour les informations de lutilisateur·rice distant·e"
remote-user-updated: "Les informations de lutilisateur·rice distant·e ont étés mis à jour"
users:
@ -1203,7 +1215,6 @@ admin/views/users.vue:
admin: "Admin"
moderator: "Modérateur"
adminOrModerator: "Administrateur/Modérateur"
verified: "Compte vérifié"
silenced: "Déjà mis en sourdine"
suspended: "Suspendu"
origin:
@ -1302,6 +1313,7 @@ admin/views/federation.vue:
chart-spans:
hour: "Par heure"
day: "Par jour"
blocked-hosts: "En cours blocage"
desktop/views/pages/welcome.vue:
about: "à propos"
timeline: "Fil dactualité"
@ -1463,6 +1475,7 @@ mobile/views/pages/drive.vue:
contextmenu:
upload: "Téléverser un fichier"
create-folder: "Créer un dossier"
rename-folder: "Renommer le dossier"
mobile/views/pages/user-lists.vue:
title: "Listes"
mobile/views/pages/signup.vue:
@ -1564,25 +1577,6 @@ deck/deck.user-column.vue:
docs:
edit-this-page-on-github: "Vous avez trouvé une erreur ou vous voulez contribuer à la documentation ?"
edit-this-page-on-github-link: "Éditez cette page sur GitHub !"
api:
entities:
properties: "Propriétés"
endpoints:
params: "Paramètres"
no-params: "Aucun paramètre"
res: "Réponse"
require-credential: "Ce point de communication nécessite une authentification."
require-permission: "Ce point de communication nécessite la permission {permission}."
has-limit: "Il ya un taux limite."
duration-limit: "Si vous avez envoyé plus de {max} requêtes en {duration} millisecondes, vous ne serez pas en mesure d'envoyer d'autres requêtes."
min-interval-limit: "Vous ne pourrez pas effectuer une nouvelle requête si {interval} millisecondes ne se sont pas écoulées depuis la dernière demande."
show-src: "Vous pouvez voir le code source ce point de communication."
show-src-link: "Consulter le code sur GitHub"
generated: "Ce document est généré à partir de la définition de lAPI."
props:
name: "Nom"
type: "Type"
description: "Description"
dev/views/index.vue:
manage-apps: "Gestion des applications"
dev/views/apps.vue:
@ -1599,3 +1593,168 @@ dev/views/new-app.vue:
authority: "Autorisations "
authority-desc: "Sont accessibles via lAPI, uniquement les fonctionnalités demandées ici."
authority-warning: "Vous pouvez le changer même après avoir créé l'application, mais si vous attribuez une nouvelle permission, toutes les clés utilisateur associées seront dès lors invalides."
pages:
page-created: "Page a été créée !"
are-you-sure-delete: "Confirmez-vous la suppression de cette page ?"
page-deleted: "La page a bien été supprimée."
edit-this-page: "Éditer cette page"
view-source: "Afficher la source"
view-page: "Afficher la page"
inspector: "Inspecteur"
content: "Bloc de page"
variables: "Variables"
more-details: "Description"
title: "Titre"
url: "URL de page"
summary: "Résumé de page"
align-center: "Centrée"
font: "Police de caractères"
fontSerif: "Serif"
fontSansSerif: "Sans Serif"
choose-block: "Ajouter un bloc"
select-type: "Choisir un type"
enter-variable-name: "Veuillez choisir un nom de variable"
the-variable-name-is-already-used: "Cette variable est déjà utilisée"
content-blocks: "Contenu du cadre"
special-blocks: "Spécial"
posted-from-post-form: "Publié !"
blocks:
text: "Texte"
textarea: "Zone de texte"
section: "Section"
image: "Images"
button: "Bouton"
if: "Si"
_if:
variable: "Variables"
post: "Champs de publication"
_post:
text: "Contenu"
textInput: "Entrée textuelle"
_textInput:
name: "Nom de la variable"
text: "Titre"
default: "Valeur par défaut"
_textareaInput:
name: "Nom de la variable"
text: "Titre"
default: "Valeur par défaut"
numberInput: "Entrée numérique"
_numberInput:
name: "Nom de la variable"
text: "Titre"
default: "Valeur par défaut"
switch: "Basculer"
_switch:
name: "Nom de la variable"
text: "Titre"
default: "Valeur par défaut"
counter: "Compteur"
_counter:
name: "Nom de la variable"
text: "Titre"
_button:
text: "Titre"
_action:
_dialog:
content: "Contenu"
script:
categories:
flow: "Contrôle"
logical: "Opération logique"
operation: "Calculer"
comparison: "Comparer"
random: "Aléatoire"
value: "Valeur"
fn: "Fonction"
list: "Listes"
blocks:
text: "Texte"
strLen: "Longueur du texte"
_strLen:
arg1: "Texte"
strPick: "Extraire un caractère"
_strPick:
arg1: "Texte"
_strReplace:
arg1: "Texte"
arg2: "Avant le remplacement"
arg3: "Après le remplacement"
strReverse: "Inverser le texte"
_strReverse:
arg1: "Texte"
_join:
arg1: "Listes"
arg2: "Séparateur"
add: "+ Plus"
_add:
arg1: "A"
arg2: "B"
subtract: "- Moins"
_subtract:
arg1: "A"
arg2: "B"
multiply: "× Multiplier par"
_multiply:
arg1: "A"
arg2: "B"
divide: "÷ Diviser par"
_divide:
arg1: "A"
arg2: "B"
_remind:
arg1: "A"
arg2: "B"
eq: "A et B sont équivalents"
_eq:
arg1: "A"
arg2: "B"
notEq: "A et B sont différents"
_notEq:
arg1: "A"
arg2: "B"
_and:
arg1: "A"
arg2: "B"
_or:
arg1: "A"
arg2: "B"
_lt:
arg1: "A"
arg2: "B"
_gt:
arg1: "A"
arg2: "B"
_ltEq:
arg1: "A"
arg2: "B"
_gtEq:
arg1: "A"
arg2: "B"
random: "Aléatoire"
_randomPick:
arg1: "Listes"
_dailyRandomPick:
arg1: "Listes"
_seedRandomPick:
arg2: "Listes"
_pick:
arg1: "Listes"
number: "Numérique"
_stringToNumber:
arg1: "Texte"
_numberToString:
arg1: "Numérique"
_splitStrByLine:
arg1: "Texte"
ref: "Variables"
fn: "Fonction"
_fn:
arg1: "Sortie"
for: "Répéter"
types:
string: "Texte"
number: "Numérique"
array: "Listes"
stringArray: "Liste de texte"
enviromentVariables: "Variables d'environnement"

View File

@ -65,6 +65,7 @@ common:
trash: "ゴミ箱"
drive: "ドライブ"
pages: "ページ"
messaging: "トーク"
home: "ホーム"
deck: "デッキ"
@ -262,7 +263,6 @@ common:
update-available-title: "更新があります"
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
verified-user: "公式アカウント"
hide-password: "パスワードを隠す"
show-password: "パスワードを表示する"
@ -338,7 +338,7 @@ auth/views/index.vue:
sign-in: "サインインしてください"
common/views/pages/explore.vue:
verified-users: "公式アカウント"
pinned-users: "ピン留めされたユーザー"
popular-users: "人気のユーザー"
recently-updated-users: "最近投稿したユーザー"
recently-registered-users: "新規ユーザー"
@ -508,6 +508,7 @@ common/views/components/nav.vue:
repository: "リポジトリ"
develop: "開発者"
feedback: "フィードバック"
tos: "利用規約"
common/views/components/note-menu.vue:
mention: "メンション"
@ -628,6 +629,8 @@ common/views/components/signup.vue:
password-matched: "確認されました"
password-not-matched: "一致していません"
recaptcha: "認証"
agree-to: "{0}に同意します。"
tos: "利用規約"
create: "アカウント作成"
some-error: "何らかの原因によりアカウントの作成に失敗しました。再度お試しください。"
@ -1184,7 +1187,6 @@ admin/views/index.vue:
users: "ユーザー"
federation: "連合"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
abuse: "スパム報告"
queue: "ジョブキュー"
logs: "ログ"
@ -1215,14 +1217,34 @@ admin/views/instance.vue:
instance-name: "インスタンス名"
instance-description: "インスタンスの紹介"
host: "ホスト"
icon-url: "アイコンURL"
logo-url: "ロゴURL"
banner-url: "バナー画像URL"
error-image-url: "エラー画像URL"
languages: "インスタンスの対象言語"
languages-desc: "スペースで区切って複数設定できます。"
tos-url: "利用規約URL"
repository-url: "リポジトリURL"
feedback-url: "フィードバックURL"
maintainer-config: "管理者情報"
maintainer-name: "管理者名"
maintainer-email: "管理者の連絡先"
advanced-config: "その他の設定"
note-and-tl: "投稿とタイムライン"
drive-config: "ドライブの設定"
use-object-storage: "オブジェクトストレージを使用する"
object-storage-base-url: "URL"
object-storage-bucket: "バケット名"
object-storage-prefix: "プレフィックス"
object-storage-endpoint: "エンドポイント"
object-storage-region: "リージョン"
object-storage-port: "ポート"
object-storage-access-key: "アクセスキー"
object-storage-secret-key: "シークレットキー"
object-storage-use-ssl: "SSLを使用"
object-storage-s3-info: "Amazon S3をオブジェクトストレージとして使用する場合の「エンドポイント」と「リージョン」の設定については{0}をご確認ください。"
object-storage-s3-info-here: "こちら"
object-storage-gcs-info: "Google Cloud Storageをオブジェクトストレージとして使用する場合、「エンドポイント」は storage.googleapis.com に設定し、「リージョン」は空欄にします。"
cache-remote-files: "リモートのファイルをキャッシュする"
cache-remote-files-desc: "この設定を無効にすると、リモートファイルをキャッシュせず直リンクするようになります。そのためサーバーのストレージを節約できますが、プライバシー設定で直リンクを無効にしているユーザーにはファイルが見えなくなったり、サムネイルが生成されないので通信量が増加します。通常はこの設定をオンにしておくことをおすすめします。"
local-drive-capacity-mb: "ローカルユーザーひとりあたりのドライブ容量"
@ -1233,6 +1255,9 @@ admin/views/instance.vue:
enable-recaptcha: "reCAPTCHAを有効にする"
recaptcha-site-key: "reCAPTCHA site key"
recaptcha-secret-key: "reCAPTCHA secret key"
hidden-tags: "非表示ハッシュタグ"
hidden-tags-info: "集計から除外するハッシュタグを改行で区切って記述します。"
external-service-integration-config: "外部サービス連携"
twitter-integration-config: "Twitter連携の設定"
twitter-integration-info: "コールバックURLは {url} に設定します。"
enable-twitter-integration: "Twitter連携を有効にする"
@ -1263,7 +1288,8 @@ admin/views/instance.vue:
invite: "招待"
save: "保存"
saved: "保存しました"
user-recommendation-config: "おすすめユーザー"
pinned-users: "ピン留めユーザー"
pinned-users-info: "ピン留めしたいユーザーを改行で区切って記述します。"
email-config: "メールサーバーの設定"
email-config-info: "メールアドレス確認やパスワードリセットの際に使われます。"
enable-email: "メール配信を有効にする"
@ -1350,14 +1376,10 @@ admin/views/users.vue:
silence-confirm: "サイレンスしますか?"
unmake-silence: "サイレンスの解除"
unsilence-confirm: "サイレンスを解除しますか?"
verify: "公式アカウントにする"
verify-confirm: "公式アカウントにしますか?"
verified: "公式アカウントにしました"
unverify: "公式アカウントを解除する"
unverify-confirm: "公式アカウントを解除しますか?"
unverified: "公式アカウントを解除しました"
update-remote-user: "リモートユーザー情報の更新"
remote-user-updated: "リモートユーザー情報を更新しました"
delete-all-files: "すべてのファイルを削除"
delete-all-files-confirm: "すべてのファイルを削除しますか?"
users:
title: "ユーザー"
sort:
@ -1372,7 +1394,6 @@ admin/views/users.vue:
admin: "管理者"
moderator: "モデレーター"
adminOrModerator: "管理者+モデレーター"
verified: "公式アカウント"
silenced: "サイレンス済み"
suspended: "凍結済み"
origin:
@ -1439,6 +1460,7 @@ admin/views/federation.vue:
latest-request-received-at: "直近のリクエスト受信"
remove-all-following: "フォローを全解除"
remove-all-following-info: "{host}からのフォローをすべて解除します。そのインスタンスがもう存在しなくなった場合などに実行してください。"
delete-all-files: "ファイルをすべて削除"
block: "ブロック"
marked-as-closed: "閉鎖されているとマーク"
lookup: "照会"
@ -1485,6 +1507,8 @@ admin/views/federation.vue:
chart-spans:
hour: "1時間ごと"
day: "1日ごと"
blocked-hosts: "ブロック"
blocked-hosts-info: "ブロックしたいホストを改行で区切って記述します。"
desktop/views/pages/welcome.vue:
about: "詳しく..."
@ -1813,26 +1837,6 @@ docs:
edit-this-page-on-github: "間違いや改善点を見つけましたか?"
edit-this-page-on-github-link: "このページをGitHubで編集"
api:
entities:
properties: "プロパティ"
endpoints:
params: "パラメータ"
no-params: "パラメータはありません"
res: "レスポンス"
require-credential: "このエンドポイントは認証情報が必須です。"
require-permission: "このエンドポイントは{permission}の権限を必要とします。"
has-limit: "レートリミットがあります。"
duration-limit: "直近{duration}ミリ秒の間のこのエンドポイントへのリクエスト数の合計が{max}を超える場合はリクエストできません。"
min-interval-limit: "前回のリクエストから{interval}ミリ秒経っていない場合はリクエストできません。"
show-src: "このエンドポイントのソースコードも閲覧できます。"
show-src-link: "コードをGitHubで見る"
generated: "このドキュメントはAPI定義に基づき自動生成されています。"
props:
name: "名前"
type: "型"
description: "説明"
dev/views/index.vue:
manage-apps: "アプリの管理"
@ -1857,3 +1861,264 @@ dev/views/new-app.vue:
authority: "権限"
authority-desc: "ここで要求した機能だけがAPIからアクセスできます。"
authority-warning: "アプリ作成後も変更できますが、新たな権限を付与する場合、その時点で関連付けられているユーザーキーはすべて無効になります。"
pages:
new-page: "ページの作成"
edit-page: "ページの編集"
read-page: "ソースを表示中"
page-created: "ページを作成しました"
page-updated: "ページを更新しました"
are-you-sure-delete: "このページを削除しますか?"
page-deleted: "ページを削除しました"
edit-this-page: "このページを編集"
view-source: "ソースを表示"
view-page: "ページを見る"
inspector: "インスペクター"
content: "ページブロック"
variables: "変数"
variables-info: "変数を使うことで動的なページを作成できます。テキスト内で <b>{ 変数名 }</b> と書くとそこに変数の値を埋め込めます。例えば <b>Hello { thing } world!</b> というテキストで、変数(thing)の値が <b>ai</b> だった場合、テキストは <b>Hello ai world!</b> になります。"
variables-info2: "変数の評価(値を算出すること)は上から下に行われるので、ある変数の中で自分より下の変数を参照することはできません。例えば上から <b>A、B、C</b> と3つの変数を定義したとき、<b>C</b>の中で<b>A</b>や<b>B</b>を参照することはできますが、<b>A</b>の中で<b>B</b>や<b>C</b>を参照することはできません。"
variables-info3: "ユーザーからの入力を受け取るには、ページに「ユーザー入力」ブロックを設置し、「変数名」に入力を格納したい変数名を設定します(変数は自動で作成されます)。その変数を使ってユーザー入力に応じた動作を行えます。"
variables-info4: "関数を使うと、値の算出処理を再利用可能な形にまとめることができます。関数を作るには、「関数」タイプの変数を作成します。関数にはスロット(引数)を設定することができ、スロットの値は関数内で変数として利用可能です。また、AiScript標準で関数を引数に取る関数(高階関数と呼ばれます)も存在します。関数は予め定義しておくほかに、このような高階関数のスロットに即席でセットすることもできます。"
more-details: "詳しい説明"
title: "タイトル"
url: "ページURL"
summary: "ページの要約"
align-center: "中央寄せ"
font: "フォント"
fontSerif: "セリフ"
fontSansSerif: "サンセリフ"
set-eye-catching-image: "アイキャッチ画像を設定"
remove-eye-catching-image: "アイキャッチ画像を削除"
choose-block: "ブロックを追加"
select-type: "種類を選択"
enter-variable-name: "変数名を決めてください"
the-variable-name-is-already-used: "その変数名は既に使われています"
content-blocks: "コンテンツ"
input-blocks: "入力"
special-blocks: "特殊"
post-from-post-form: "この内容を投稿"
posted-from-post-form: "投稿しました"
blocks:
text: "テキスト"
textarea: "テキストエリア"
section: "セクション"
image: "画像"
button: "ボタン"
if: "もし"
_if:
variable: "変数"
post: "投稿フォーム"
_post:
text: "内容"
textInput: "テキスト入力"
_textInput:
name: "変数名"
text: "タイトル"
default: "デフォルト値"
textareaInput: "複数行テキスト入力"
_textareaInput:
name: "変数名"
text: "タイトル"
default: "デフォルト値"
numberInput: "数値入力"
_numberInput:
name: "変数名"
text: "タイトル"
default: "デフォルト値"
switch: "スイッチ"
_switch:
name: "変数名"
text: "タイトル"
default: "デフォルト値"
counter: "カウンター"
_counter:
name: "変数名"
text: "タイトル"
inc: "増加値"
_button:
text: "タイトル"
action: "ボタンを押したときの動作"
_action:
dialog: "ダイアログを表示する"
_dialog:
content: "内容"
resetRandom: "乱数をリセット"
script:
categories:
flow: "制御"
logical: "論理演算"
operation: "計算"
comparison: "比較"
random: "ランダム"
value: "値"
fn: "関数"
text: "テキスト操作"
convert: "変換"
list: "リスト"
blocks:
text: "テキスト"
multiLineText: "テキスト(複数行)"
textList: "テキストのリスト"
_textList:
info: "ひとつひとつを改行で区切ってください"
strLen: "テキストの長さ"
_strLen:
arg1: "テキスト"
strPick: "文字取り出し"
_strPick:
arg1: "テキスト"
arg2: "文字の位置"
strReplace: "テキスト置き換え"
_strReplace:
arg1: "テキスト"
arg2: "置き換え前"
arg3: "置き換え後"
strReverse: "テキストを反転"
_strReverse:
arg1: "テキスト"
join: "テキストを連結"
_join:
arg1: "リスト"
arg2: "区切り"
add: "+ 足す"
_add:
arg1: "A"
arg2: "B"
subtract: "- 引く"
_subtract:
arg1: "A"
arg2: "B"
multiply: "× 掛ける"
_multiply:
arg1: "A"
arg2: "B"
divide: "÷ 割る"
_divide:
arg1: "A"
arg2: "B"
remind: "÷ 割った余り"
_remind:
arg1: "A"
arg2: "B"
eq: "AとBが同じ"
_eq:
arg1: "A"
arg2: "B"
notEq: "AとBが異なる"
_notEq:
arg1: "A"
arg2: "B"
and: "AかつB"
_and:
arg1: "A"
arg2: "B"
or: "AまたはB"
_or:
arg1: "A"
arg2: "B"
lt: "< AがBより小さい"
_lt:
arg1: "A"
arg2: "B"
gt: "> AがBより大きい"
_gt:
arg1: "A"
arg2: "B"
ltEq: "<= AがBと同じか小さい"
_ltEq:
arg1: "A"
arg2: "B"
gtEq: ">= AがBと同じか大きい"
_gtEq:
arg1: "A"
arg2: "B"
if: "分岐"
_if:
arg1: "もし"
arg2: "なら"
arg3: "そうでなければ"
not: "否定"
_not:
arg1: "否定"
random: "ランダム"
_random:
arg1: "確率"
rannum: "乱数"
_rannum:
arg1: "最小"
arg2: "最大"
randomPick: "リストからランダムに選択"
_randomPick:
arg1: "リスト"
dailyRandom: "ランダム (ユーザーごとに日替わり)"
_dailyRandom:
arg1: "確率"
dailyRannum: "乱数 (ユーザーごとに日替わり)"
_dailyRannum:
arg1: "最小"
arg2: "最大"
dailyRandomPick: "リストからランダムに選択 (ユーザーごとに日替わり)"
_dailyRandomPick:
arg1: "リスト"
seedRandom: "ランダム (シード)"
_seedRandom:
arg1: "シード"
arg2: "確率"
seedRannum: "乱数 (シード)"
_seedRannum:
arg1: "シード"
arg2: "最小"
arg3: "最大"
seedRandomPick: "リストからランダムに選択 (シード)"
_seedRandomPick:
arg1: "シード"
arg2: "リスト"
DRPWPM: "確率付きリストからランダムに選択 (ユーザーごとに日替わり)"
_DRPWPM:
arg1: "テキストのリスト"
pick: "リストから選択"
_pick:
arg1: "リスト"
arg2: "位置"
number: "数値"
stringToNumber: "テキストを数値に"
_stringToNumber:
arg1: "テキスト"
numberToString: "数値をテキストに"
_numberToString:
arg1: "数値"
splitStrByLine: "テキストを行で分割"
_splitStrByLine:
arg1: "テキスト"
ref: "変数"
fn: "関数"
_fn:
slots: "スロット"
slots-info: "スロットひとつひとつを改行で区切ってください"
arg1: "出力"
for: "繰り返し"
_for:
arg1: "回数"
arg2: "処理"
typeError: "スロット{slot}は\"{expect}\"を受け付けますが、\"{actual}\"が入れられています!"
thereIsEmptySlot: "スロット{slot}が空です!"
types:
string: "テキスト"
number: "数値"
boolean: "フラグ"
array: "リスト"
stringArray: "テキストのリスト"
emptySlot: "空のスロット"
enviromentVariables: "環境変数"
pageVariables: "ページ要素"
argVariables: "入力スロット"

View File

@ -121,7 +121,6 @@ common:
update-available-title: "更新があんで"
update-available: "Misskeyの新しいバージョンがあんで({newer}。現在{current}をつこてるわ)。ページを再度読み込みしたると更新が適用されるわ。"
my-token-regenerated: "あんさんのトークンが更新されたらしいわ。すまんがとりあえずサインアウトすんで。"
verified-user: "アメちゃん付きアカウント"
do-not-use-in-production: "開発ビルドや。本番環境で使わんといて!知らんで!"
is-remote-post: "この投稿情報はコピーです。"
view-on-remote: "ちゃんとした情報見せてや!"
@ -181,7 +180,6 @@ auth/views/index.vue:
error: "セッションが存在してへん。"
sign-in: "サインインしてや"
common/views/pages/explore.vue:
verified-users: "アメちゃん付きアカウント"
federated: "連合"
common/views/components/games/reversi/reversi.vue:
matching:
@ -899,7 +897,6 @@ admin/views/instance.vue:
invite: "来てや"
save: "保存"
saved: "保存したで!"
user-recommendation-config: "このユーザーええで"
email-config: "メールサーバーの設定"
email-config-info: "メールアドレス確認やパスワードリセットの際に使うで。"
enable-email: "メール配信を有効にする"
@ -956,7 +953,6 @@ admin/views/users.vue:
state:
all: "すべて"
moderator: "モデレーター"
verified: "アメちゃん付きアカウント"
origin:
local: "ローカル"
admin/views/emoji.vue:
@ -995,6 +991,7 @@ admin/views/federation.vue:
chart-spans:
hour: "1時間ごと"
day: "1日ごと"
blocked-hosts: "ブロック"
desktop/views/pages/welcome.vue:
about: "もうちょい……"
timeline: "タイムライン"
@ -1246,25 +1243,6 @@ deck/deck.user-column.vue:
docs:
edit-this-page-on-github: "間違いや改善点を見つけましたか?"
edit-this-page-on-github-link: "このページをGitHubで編集"
api:
entities:
properties: "プロパティ"
endpoints:
params: "パラメータ"
no-params: "パラメータはありません"
res: "レスポンス"
require-credential: "このエンドポイントは認証情報が必須です。"
require-permission: "このエンドポイントは{permission}の権限を必要とします。"
has-limit: "レートリミットがあります。"
duration-limit: "直近{duration}ミリ秒の間のこのエンドポイントへのリクエスト数の合計が{max}を超える場合はリクエストできません。"
min-interval-limit: "前回のリクエストから{interval}ミリ秒経っていない場合はリクエストできません。"
show-src: "このエンドポイントのソースコードも閲覧できます。"
show-src-link: "コードをGitHubで見る"
generated: "このドキュメントはAPI定義に基づき自動生成されています。"
props:
name: "名前"
type: "型"
description: "説明"
dev/views/index.vue:
manage-apps: "アプリの管理"
dev/views/apps.vue:
@ -1281,3 +1259,25 @@ dev/views/new-app.vue:
authority: "権限"
authority-desc: "ここにチェックした機能しかAPIからアクセスできひんから気ぃつけてな"
authority-warning: "アプリ作った後でも変えれるけど、新しいやつ追加したらそん時関連付いてるユーザーキーは全部ほかされるで。"
pages:
blocks:
image: "画像"
post: "投稿フォーム"
script:
categories:
random: "いんじゃんほい"
list: "リスト"
blocks:
_join:
arg1: "リスト"
random: "いんじゃんほい"
_randomPick:
arg1: "リスト"
_dailyRandomPick:
arg1: "リスト"
_seedRandomPick:
arg2: "リスト"
_pick:
arg1: "リスト"
types:
array: "リスト"

View File

@ -34,6 +34,7 @@ common:
signup: "신규 등록"
signout: "로그아웃"
reload-to-apply-the-setting: "이 설정을 적용하려면 페이지를 새로고침해야 합니다. 바로 새로고침하시겠습니까?"
fetching-as-ap-object: "연합에서 조회 중"
got-it: "알겠습니다"
customization-tips:
title: "커스터마이징 도움말"
@ -61,6 +62,7 @@ common:
month-and-day: "{month}월 {day}일"
trash: "휴지통"
drive: "드라이브"
pages: "페이지"
messaging: "대화"
home: "홈"
deck: "덱"
@ -72,8 +74,23 @@ common:
permissions:
"read:account": "계정 정보 보기"
"write:account": "계정 정보 변경"
"read:blocks": "차단 보기"
"write:blocks": "차단 수정"
"read:drive": "드라이브 보기"
"write:drive": "드라이브 수정"
"read:favorites": "즐겨찾기 보기"
"write:favorites": "즐겨찾기 수정"
"read:following": "팔로우 정보 보기"
"write:following": "팔로잉, 팔로우 수정"
"read:messaging": "대화 보기"
"write:messaging": "대화 수정"
"read:mutes": "뮤트 보기"
"write:mutes": "뮤트 수정"
"write:notes": "글 작성, 삭제"
"read:notifications": "글 보기"
"write:notifications": "알림 수정"
"read:reactions": "리액션 보기"
"write:reactions": "리액션 수정"
"write:votes": "투표하기"
empty-timeline-info:
follow-users-to-make-your-timeline: "사용자를 팔로우하면 글이 타임라인에 표시됩니다."
@ -234,7 +251,6 @@ common:
update-available-title: "업데이트가 있습니다"
update-available: "Misskey의 새로운 버전이 있습니다 ({newer}. 현재 {current}을 사용 중). 페이지를 다시 로드하면 업데이트가 적용됩니다."
my-token-regenerated: "당신의 토큰이 업데이트되었으므로 로그아웃합니다."
verified-user: "공식 계정"
hide-password: "비밀번호 숨기기"
show-password: "비밀번호 표시"
do-not-use-in-production: "이것은 개발 빌드입니다. 프로덕션 환경에서 사용하지 마십시오."
@ -277,7 +293,7 @@ common:
notifications: "알림"
users: "추천 사용자"
polls: "투표"
post-form: "게시 양식"
post-form: "글 입력란"
server: "서버 정보"
nav: "내비게이션"
tips: "팁"
@ -293,16 +309,16 @@ auth/views/form.vue:
accept: "접근 권한 허용"
auth/views/index.vue:
loading: "로드 중"
denied: "플리케이션의 연계를 취소하였습니다."
denied: "플리케이션의 연계를 취소하였습니다."
denied-paragraph: "이 앱이 당신의 계정에 액세스할 수 없습니다."
already-authorized: "이 앱은 이미 연결되어 있습니다."
allowed: "플리케이션의 연동을 허용하였습니다."
callback-url: "플리케이션으로 돌아갑니다."
please-go-back: "플리케이션으로 돌아가여 시도하여 주십시오."
allowed: "플리케이션의 연동을 허용하였습니다."
callback-url: "플리케이션으로 돌아갑니다."
please-go-back: "플리케이션으로 돌아가여 시도하여 주십시오."
error: "세션이 존재하지 않습니다."
sign-in: "로그인 해주시기 바랍니다"
common/views/pages/explore.vue:
verified-users: "공식 계정"
pinned-users: "고정된 사용자"
popular-users: "인기 사용자"
recently-updated-users: "최근 게시한 사용자"
recently-registered-users: "신규 사용자"
@ -456,6 +472,7 @@ common/views/components/nav.vue:
repository: "저장소"
develop: "개발자"
feedback: "피드백"
tos: "이용 약관"
common/views/components/note-menu.vue:
mention: "멘션"
detail: "상세"
@ -474,8 +491,12 @@ common/views/components/user-menu.vue:
mention: "멘션"
mute: "뮤트"
unmute: "뮤트 해제"
mute-confirm: "이 사용자를 뮤트하시겠습니까?"
unmute-confirm: "이 사용자를 뮤트 해제하시겠습니까?"
block: "차단"
unblock: "차단 해제"
block-confirm: "이 사용자를 차단하시겠습니까?"
unblock-confirm: "이 사용자를 차단 해제하시겠습니까?"
push-to-list: "리스트에 추가"
select-list: "리스트를 선택하여 주십시오"
report-abuse: "스팸 신고"
@ -483,8 +504,12 @@ common/views/components/user-menu.vue:
report-abuse-reported: "관리자에게 보고되었습니다. 협조해주셔서 감사합니다."
silence: "침묵"
unsilence: "침묵 해제"
silence-confirm: "이 사용자를 침묵하시겠습니까?"
unsilence-confirm: "이 사용자를 침묵 해제하시겠습니까?"
suspend: "정지"
unsuspend: "정지 해제"
suspend-confirm: "이 사용자를 정지하시겠습니까?"
unsuspend-confirm: "이 사용자를 정지 해제하시겠습니까?"
common/views/components/poll.vue:
vote-to: "\"{}\"에 투표하기"
vote-count: "{}표"
@ -560,6 +585,7 @@ common/views/components/signup.vue:
password-matched: "확인되었습니다"
password-not-matched: "일치하지 않습니다"
recaptcha: "자동 가입 방지"
tos: "이용 약관"
create: "계정 만들기"
some-error: "알 수 없는 이유로 계정 만들기에 실패했습니다. 다시 한번 시도해 주세요."
common/views/components/special-message.vue:
@ -668,6 +694,7 @@ common/views/components/user-list-editor.vue:
delete-are-you-sure: "리스트 \"$1\"을 삭제하시겠습니까?"
deleted: "삭제하였습니다"
common/views/components/user-lists.vue:
create-list: "리스트 만들기"
list-name: "리스트 이름"
common/views/widgets/broadcast.vue:
fetching: "확인중"
@ -946,7 +973,7 @@ common/views/components/api-settings.vue:
sending: "응답을 기다리는 중"
response: "결과"
desktop/views/components/settings.apps.vue:
no-apps: "연결된 플리케이션이 없습니다"
no-apps: "연결된 플리케이션이 없습니다"
common/views/components/drive-settings.vue:
max: "최대 용량"
in-use: "사용중"
@ -1065,10 +1092,15 @@ admin/views/instance.vue:
instance-name: "인스턴스 이름"
instance-description: "인스턴스의 소개"
host: "관리자"
icon-url: "아이콘 URL"
logo-url: "로고 URL"
banner-url: "배너 이미지 URL"
error-image-url: "오류 이미지 URL"
languages: "인스턴스의 대상 언어"
languages-desc: "공백으로 구분하여 여러 개 설정할 수 있습니다."
tos-url: "이용약관 URL"
repository-url: "저장소 URL"
feedback-url: "피드백 URL"
maintainer-config: "관리자 정보"
maintainer-name: "관리자 이름"
maintainer-email: "관리자 연락처"
@ -1113,7 +1145,7 @@ admin/views/instance.vue:
invite: "초대"
save: "저장"
saved: "저장하였습니다"
user-recommendation-config: "추천 사용자"
pinned-users: "고정된 사용자"
email-config: "메일 서버 설정"
email-config-info: "메일 주소 확인 혹은 비밀번호 재설정에 사용 됩니다."
enable-email: "메일 발신 활성화"
@ -1194,13 +1226,9 @@ admin/views/users.vue:
unsuspend-confirm: "정지를 해제하시겠습니까?"
unsuspended: "정지를 해제하였습니다"
make-silence: "침묵"
silence-confirm: "침묵으로 설정합니까?"
unmake-silence: "침묵 해제"
verify: "공식 계정으로 설정"
verify-confirm: "공식 계정으로 설정하시겠습니까?"
verified: "공식 계정으로 설정하였습니다"
unverify: "공식 계정 해제"
unverify-confirm: "공식 계정을 해제하시겠습니까?"
unverified: "공식 계정을 해제하였습니다"
unsilence-confirm: "침묵 해제하시겠습니까?"
update-remote-user: "원격 사용자 정보 갱신"
remote-user-updated: "원격 사용자 정보를 갱신하였습니다"
users:
@ -1217,7 +1245,6 @@ admin/views/users.vue:
admin: "관리자"
moderator: "모더레이터"
adminOrModerator: "관리자+모더레이터"
verified: "공식 계정"
silenced: "침묵됨"
suspended: "정지됨"
origin:
@ -1325,6 +1352,7 @@ admin/views/federation.vue:
chart-spans:
hour: "1시간마다"
day: "1일마다"
blocked-hosts: "차단"
desktop/views/pages/welcome.vue:
about: "자세히..."
timeline: "타임라인"
@ -1388,6 +1416,7 @@ desktop/views/widgets/polls.vue:
desktop/views/widgets/post-form.vue:
title: "글쓰기"
note: "글쓰기"
something-happened: "알 수 없는 문제로 글을 게시할 수 없습니다."
desktop/views/widgets/profile.vue:
update-banner: "클릭하여 배너 변경"
update-avatar: "클릭하여 아바타 변경"
@ -1410,6 +1439,7 @@ mobile/views/components/drive.vue:
here-is-root: "현재 경로는 루트 경로로 폴더가 아닙니다."
url-prompt: "업로드 하려는 파일의 URL"
uploading: "업로드를 요청하였습니다. 업로드가 완료될 때까지 시간이 소요될 수 있습니다."
folder-name-cannot-empty: "폴더 이름은 비워둘 수 없습니다."
mobile/views/components/drive-file-chooser.vue:
select-file: "파일 선택"
mobile/views/components/drive-folder-chooser.vue:
@ -1486,7 +1516,11 @@ mobile/views/components/ui.nav.vue:
mobile/views/pages/drive.vue:
contextmenu:
upload: "파일 업로드"
url-upload: "파일을 URL로부터 업로드"
create-folder: "폴더 만들기"
rename-folder: "폴더 이름 바꾸기"
move-folder: "이 폴더를 이동"
delete-folder: "이 폴더를 삭제"
mobile/views/pages/user-lists.vue:
title: "리스트"
mobile/views/pages/signup.vue:
@ -1589,25 +1623,6 @@ deck/deck.user-column.vue:
docs:
edit-this-page-on-github: "틀린 점이나 개선할 점을 찾으셨나요?"
edit-this-page-on-github-link: "이 페이지를 GitHub에서 편집"
api:
entities:
properties: "프로퍼티"
endpoints:
params: "매개변수"
no-params: "매개변수가 없습니다"
res: "응답"
require-credential: "이 엔드포인트는 인증 정보가 필수적입니다."
require-permission: "이 엔드포인트는 {permission} 권한을 필요로 합니다."
has-limit: "Rate limit(요청 비율 제한)이 있습니다."
duration-limit: "최근 {duration} 밀리초 사이에 엔드포인트로의 요청 수의 합계가 {max}를 넘는 경우 요청이 불가능합니다."
min-interval-limit: "이전 요청으로부터 {interval} 밀리초가 지나지 않은 경우 요청할 수 없습니다."
show-src: "이 엔드포인트에 대한 소스코드를 확인할 수 있습니다."
show-src-link: "코드를 Github에서 보기"
generated: "이 문서는 API 정의를 기반으로 자동으로 생성됩니다."
props:
name: "이름"
type: "자료형"
description: "설명"
dev/views/index.vue:
manage-apps: "앱 관리"
dev/views/apps.vue:
@ -1615,12 +1630,246 @@ dev/views/apps.vue:
create-app: "앱 생성"
app-missing: "앱 없음"
dev/views/new-app.vue:
create-app: "플리케이션 생성"
app-name: "플리케이션 이름"
new-app: "새 애플리케이션"
new-app-info: "플리케이션은 API에서도 생성할 수 있습니다. (app/create)"
create-app: "애플리케이션 생성"
app-name: "애플리케이션 이름"
app-name-placeholder: "ex) Misskey for iOS"
app-name-desc: "앱의 이름."
app-overview: "앱 개요"
app-overview-placeholder: "ex) Misskey iOS 클라이언트."
app-overview-desc: "애플리케이션에 대한 간단한 설명이나 소개"
callback-url: "콜백 URL (옵션)"
callback-url-placeholder: "ex) https://your.app.example.com/callback.php"
callback-url-desc: "사용자가 인증 폼에서 인증한 뒤 리다이렉트할 URL을 설정합니다."
authority: "권한"
authority-desc: "이곳에서 요청한 권한에 한정하여 API로 액세스할 수 있습니다."
authority-warning: "앱을 생성한 뒤에도 변경할 수 있지만, 새로운 권한을 설정하는 경우 그 시점부터 예전에 발급받았던 유저 키는 모두 무효화됩니다."
pages:
new-page: "페이지 만들기"
edit-page: "페이지 수정"
read-page: "소스 표시중"
page-created: "페이지를 만들었습니다"
page-updated: "페이지를 수정했습니다"
are-you-sure-delete: "이 페이지를 삭제하시겠습니까?"
page-deleted: "페이지가 삭제되었습니다"
edit-this-page: "이 페이지를 편집"
view-source: "소스 보기"
view-page: "페이지 보기"
inspector: "인스펙터"
content: "페이지 블록"
variables: "변수"
more-details: "자세한 설명"
title: "제목"
url: "페이지 URL"
summary: "페이지 요약"
align-center: "가운데 정렬"
font: "글꼴"
fontSerif: "세리프"
fontSansSerif: "산 세리프"
set-eye-catching-image: "아이캐치 이미지를 설정"
remove-eye-catching-image: "아이캐치 이미지를 삭제"
choose-block: "블록 추가"
select-type: "종류 선택"
enter-variable-name: "변수명을 설정해주십시오"
the-variable-name-is-already-used: "그 변수명은 이미 사용중입니다"
content-blocks: "콘텐츠"
input-blocks: "입력"
special-blocks: "특수"
post-from-post-form: "이 내용을 올리기"
posted-from-post-form: "게시하였습니다"
blocks:
text: "텍스트"
textarea: "텍스트 영역"
section: "섹션"
image: "이미지"
button: "버튼"
if: "만약"
_if:
variable: "변수"
post: "글 입력란"
_post:
text: "내용"
textInput: "텍스트 입력"
_textInput:
name: "변수명"
text: "제목"
default: "기본값"
textareaInput: "여러 줄 텍스트 입력"
_textareaInput:
name: "변수명"
text: "제목"
default: "기본값"
numberInput: "수치 입력"
_numberInput:
name: "변수명"
text: "제목"
default: "기본값"
switch: "스위치"
_switch:
name: "변수명"
text: "제목"
default: "기본값"
counter: "카운터"
_counter:
name: "변수명"
text: "제목"
inc: "증가치"
_button:
text: "제목"
action: "버튼을 눌렀을 때의 동작"
_action:
dialog: "대화상자를 표시"
_dialog:
content: "내용"
resetRandom: "난수를 초기화"
script:
categories:
flow: "흐름 제어"
logical: "논리 연산"
operation: "계산"
comparison: "비교"
random: "랜덤"
value: "값"
fn: "함수"
text: "텍스트 조작"
convert: "변환"
list: "리스트"
blocks:
text: "텍스트"
multiLineText: "텍스트 (여러줄)"
textList: "텍스트 목록"
strLen: "텍스트의 길이"
_strLen:
arg1: "텍스트"
strPick: "문자 추출"
_strPick:
arg1: "텍스트"
arg2: "문자 위치"
strReplace: "텍스트 치환"
_strReplace:
arg1: "텍스트"
arg2: "치환 전"
arg3: "치환 후"
strReverse: "텍스트 뒤집기"
_strReverse:
arg1: "텍스트"
join: "텍스트 접합"
_join:
arg1: "리스트"
arg2: "구분자"
add: "+ 더하기"
_add:
arg1: "A"
arg2: "B"
subtract: "- 빼기"
_subtract:
arg1: "A"
arg2: "B"
multiply: "× 곱하기"
_multiply:
arg1: "A"
arg2: "B"
divide: "÷ 나누기"
_divide:
arg1: "A"
arg2: "B"
remind: "÷ 나눈 나머지"
_remind:
arg1: "A"
arg2: "B"
eq: "A와 B가 동일"
_eq:
arg1: "A"
arg2: "B"
notEq: "A와 B가 다름"
_notEq:
arg1: "A"
arg2: "B"
and: "A 그리고 B"
_and:
arg1: "A"
arg2: "B"
or: "A 혹은 B"
_or:
arg1: "A"
arg2: "B"
lt: "< A가 B보다 작음"
_lt:
arg1: "A"
arg2: "B"
gt: "> A가 B보다 큼"
_gt:
arg1: "A"
arg2: "B"
ltEq: "<= A가 B보다 작거나 같음"
_ltEq:
arg1: "A"
arg2: "B"
gtEq: ">= A가 B보다 크거나 같음"
_gtEq:
arg1: "A"
arg2: "B"
if: "분기"
_if:
arg1: "만약"
arg2: "그러면"
arg3: "그렇지 않으면"
not: "부정"
_not:
arg1: "부정"
random: "랜덤"
_random:
arg1: "확률"
rannum: "난수"
_rannum:
arg1: "최소"
arg2: "최대"
randomPick: "목록에서 임의로 선택"
_randomPick:
arg1: "리스트"
_dailyRandom:
arg1: "확률"
_dailyRannum:
arg1: "최소"
arg2: "최대"
_dailyRandomPick:
arg1: "리스트"
_seedRandom:
arg1: "시드"
arg2: "확률"
_seedRannum:
arg1: "시드"
arg2: "최소"
arg3: "최대"
_seedRandomPick:
arg1: "시드"
arg2: "리스트"
_DRPWPM:
arg1: "텍스트 목록"
_pick:
arg1: "리스트"
number: "수치"
stringToNumber: "텍스트를 수치로"
_stringToNumber:
arg1: "텍스트"
_numberToString:
arg1: "수치"
_splitStrByLine:
arg1: "텍스트"
ref: "변수"
fn: "함수"
_fn:
slots: "슬롯"
arg1: "출력"
thereIsEmptySlot: "슬롯 {slot}이(가) 비었습니다!"
types:
string: "텍스트"
number: "수치"
boolean: "플래그"
array: "리스트"
stringArray: "텍스트 목록"
emptySlot: "빈 슬롯"
enviromentVariables: "환경 변수"
pageVariables: "페이지 요소"
argVariables: "입력 슬롯"

View File

@ -422,8 +422,6 @@ admin/views/dashboard.vue:
notes: "Bericht"
admin/views/abuse.vue:
remove-report: "Verwijderen"
admin/views/instance.vue:
user-recommendation-config: "Aanbevolen gebruikers"
admin/views/charts.vue:
notes: "Bericht"
users: "Gebruiker"
@ -619,13 +617,22 @@ deck/deck.user-column.vue:
docs:
edit-this-page-on-github: "Heb je een fout ontdekt of wil je bijdragen aan de documentatie? "
edit-this-page-on-github-link: "Bewerk deze pagina op GitHub!"
api:
entities:
properties: "Eigenschappen"
endpoints:
params: "Parameters"
res: "Antwoord"
props:
name: "Naam"
type: "Type"
description: "Omschrijving"
pages:
blocks:
image: "Afbeeldingen"
script:
categories:
list: "Lijsten"
blocks:
_join:
arg1: "Lijsten"
_randomPick:
arg1: "Lijsten"
_dailyRandomPick:
arg1: "Lijsten"
_seedRandomPick:
arg2: "Lijsten"
_pick:
arg1: "Lijsten"
types:
array: "Lijsten"

View File

@ -489,14 +489,24 @@ deck/deck.user-column.vue:
following: "Følger"
followers: "Følgere"
images: "Bilder"
docs:
api:
entities:
properties: "Egenskaper"
endpoints:
params: "Parametere"
res: "Respons"
props:
name: "Navn"
type: "Type"
description: "Beskrivelse"
pages:
blocks:
image: "Bilder"
script:
categories:
random: "Tilfeldig"
list: "Lister"
blocks:
_join:
arg1: "Lister"
random: "Tilfeldig"
_randomPick:
arg1: "Lister"
_dailyRandomPick:
arg1: "Lister"
_seedRandomPick:
arg2: "Lister"
_pick:
arg1: "Lister"
types:
array: "Lister"

View File

@ -54,6 +54,7 @@ common:
month-and-day: "{month}-{day}"
trash: "Kosz"
drive: "Dysk"
pages: "Strony"
messaging: "Rozmowy"
home: "Strona główna"
deck: "Tablice"
@ -127,6 +128,7 @@ common:
behavior: "Zachowanie"
fetch-on-scroll: "Automatycznie ładuj po przeciągnięciu w dół"
note-visibility: "Widoczność wpisów"
remember-note-visibility: "Zapamiętaj widoczność wpisów"
web-search-engine: "Wyszukiwarka internetowa"
line-width: "Szerokości linii"
line-width-thin: "Cienka"
@ -164,7 +166,6 @@ common:
update-available-title: "Aktualizacja jest dostępna"
update-available: "Nowa wersja Misskey jest dostępna ({newer}, obecna to {current}). Odśwież stronę, aby zastosować aktualizację."
my-token-regenerated: "Twój token został wygenerowany. Zostaniesz wylogowany."
verified-user: "Zweryfikowane konto"
hide-password: "Ukryj hasło"
show-password: "Pokaż hasło"
view-on-remote: "Dla dopełnienia, zobacz to zdalnie."
@ -216,8 +217,6 @@ auth/views/index.vue:
please-go-back: "Wróć do aplikacji."
error: "Sesja nie istnieje."
sign-in: "Proszę zalogować się."
common/views/pages/explore.vue:
verified-users: "Zweryfikowane konto"
common/views/components/games/reversi/reversi.vue:
matching:
waiting-for: "Oczekiwanie na {}"
@ -875,7 +874,6 @@ admin/views/instance.vue:
invite: "Zaproś"
save: "Zapisz"
saved: "Zapisano"
user-recommendation-config: "Polecani użytkownicy"
email: "Adres e-mail"
admin/views/charts.vue:
notes: "Wpisy"
@ -905,7 +903,6 @@ admin/views/users.vue:
state:
all: "Wszyscy"
moderator: "Moderatorzy"
verified: "Zweryfikowane konto"
origin:
title: "Źródło"
local: "Lokalny"
@ -951,6 +948,7 @@ admin/views/federation.vue:
blocked: "Zablokuj"
chart-srcs:
requests: "Żądania"
blocked-hosts: "Zablokuj"
desktop/views/pages/welcome.vue:
about: "O Misskey"
timeline: "Oś czasu"
@ -1190,23 +1188,6 @@ deck/deck.user-column.vue:
docs:
edit-this-page-on-github: "Znalazłeś błąd lub chcesz pomóc w tworzeniu dokumentacji?"
edit-this-page-on-github-link: "Edytuj stronę na GitHubie!"
api:
entities:
properties: "Właściwości"
endpoints:
params: "Parametry"
no-params: "Brak parametrów."
res: "Odpowiedź"
require-credential: "Punkt końcowy wymaga informacji o uwierzytelnieniu."
require-permission: "Ten punkt końcowy wymaga uprawnienia {permission}."
has-limit: "Istnieje limit częstotliwości."
min-interval-limit: "Nie możesz wykonać żądania przed upłynięciem {interval} od ostatniego żądania."
show-src: "Możesz zobaczyć kod źródłowy tego punktu końcowego."
show-src-link: "Zobacz kod na GitHubie"
props:
name: "Nazwa"
type: "Rodzaj"
description: "Opis"
dev/views/index.vue:
manage-apps: "Zarządzaj aplikacjami"
dev/views/apps.vue:
@ -1215,3 +1196,38 @@ dev/views/apps.vue:
dev/views/new-app.vue:
app-name: "Nazwa Aplikacji"
authority: "Uprawnienia"
pages:
title: "Tytuł"
blocks:
image: "Zdjęcia"
post: "Formularz tworzenia"
_textInput:
text: "Tytuł"
_textareaInput:
text: "Tytuł"
_numberInput:
text: "Tytuł"
_switch:
text: "Tytuł"
_counter:
text: "Tytuł"
_button:
text: "Tytuł"
script:
categories:
random: "Losowy"
list: "Listy"
blocks:
_join:
arg1: "Listy"
random: "Losowy"
_randomPick:
arg1: "Listy"
_dailyRandomPick:
arg1: "Listy"
_seedRandomPick:
arg2: "Listy"
_pick:
arg1: "Listy"
types:
array: "Listy"

View File

@ -89,7 +89,6 @@ common:
update-available-title: "Atualização disponível"
update-available: "Uma nova versão de Misskey está disponível ({newer}). A versão atual é {current}. Recarregue a página para atualizar."
my-token-regenerated: "Seu token foi recriado, portanto você foi deslogado."
verified-user: "Conta verificada"
reversi:
drawn: "Empatado"
my-turn: "Seu turno"
@ -129,8 +128,6 @@ auth/views/index.vue:
please-go-back: "Por favor, volte ao aplicativo."
error: "A sessão não existe."
sign-in: "Por favor, entre."
common/views/pages/explore.vue:
verified-users: "Conta verificada"
common/views/components/games/reversi/reversi.index.vue:
invite: "Convidar"
rule: "Como jogar"
@ -194,10 +191,6 @@ admin/views/instance.vue:
invite: "Convidar"
admin/views/drive.vue:
delete: "Apagar"
admin/views/users.vue:
users:
state:
verified: "Conta verificada"
admin/views/emoji.vue:
emojis:
remove: "Apagar"
@ -274,18 +267,9 @@ deck/deck.user-column.vue:
timeline: "Linha do tempo"
docs:
edit-this-page-on-github-link: "Edite esta página no GitHub!"
api:
entities:
properties: "Propriedades"
endpoints:
params: "Parâmetros"
no-params: "Sem parâmetros"
res: "Resposta"
show-src-link: "Veja o código no GitHub"
generated: "Este documento foi gerado pelas definições da API."
props:
name: "Nome"
type: "Tipo"
description: "Descrição"
dev/views/index.vue:
manage-apps: "Gerenciar aplicativos"
pages:
blocks:
image: "Imagens"
post: "Formulário de publicação"

View File

@ -146,3 +146,9 @@ mobile/views/components/sub-note-content.vue:
poll: "Голосования"
mobile/views/pages/widgets.vue:
customization-tips: "Советы по настройке"
pages:
script:
categories:
random: "Случайно"
blocks:
random: "Случайно"

View File

@ -34,6 +34,7 @@ common:
signup: "注册"
signout: "退出"
reload-to-apply-the-setting: "必须重新加载页面以应用此设置。 确实要立即重新加载吗?"
fetching-as-ap-object: "联合查询"
got-it: "知道了"
customization-tips:
title: "自定义提示"
@ -61,6 +62,7 @@ common:
month-and-day: "{month}月 {day}日"
trash: "垃圾箱"
drive: "网盘"
pages: "页面"
messaging: "聊天"
home: "首页"
deck: "Deck"
@ -249,7 +251,6 @@ common:
update-available-title: "有可用更新"
update-available: "新的 Misskey 版本现已发布({newer}。目前版本{current}). 刷新页面以应用更新。"
my-token-regenerated: "您的 Token 已被重置, 您将自动登出。"
verified-user: "认证用户"
hide-password: "隐藏密码"
show-password: "显示密码"
do-not-use-in-production: "这是一个开发者测试版. 请勿在生产环境中使用."
@ -317,7 +318,7 @@ auth/views/index.vue:
error: "会话不存在。"
sign-in: "请登录。"
common/views/pages/explore.vue:
verified-users: "官方账户"
pinned-users: "已置顶用户"
popular-users: "热门用户"
recently-updated-users: "活跃用户"
recently-registered-users: "新用户"
@ -1137,7 +1138,7 @@ admin/views/instance.vue:
invite: "邀请"
save: "保存"
saved: "保存完毕"
user-recommendation-config: "推荐用户"
pinned-users: "置顶用户"
email-config: "电子邮件服务器设置"
email-config-info: "用于确认电子邮件和密码重置等。"
enable-email: "启用电子邮件送递"
@ -1221,12 +1222,6 @@ admin/views/users.vue:
silence-confirm: "确认屏蔽?"
unmake-silence: "解除禁言"
unsilence-confirm: "解除屏蔽?"
verify: "认证用户"
verify-confirm: "是否官方账号?"
verified: "此账户已被认证"
unverify: "解除账户认证"
unverify-confirm: "是否解除官方账号认证?"
unverified: "该帐户未经认证"
update-remote-user: "更新远程用户信息"
remote-user-updated: "远程用户信息已更新"
users:
@ -1243,7 +1238,6 @@ admin/views/users.vue:
admin: "管理员"
moderator: "版主"
adminOrModerator: "管理员+版主"
verified: "官方认证账户"
silenced: "已禁言"
suspended: "已冻结"
origin:
@ -1351,6 +1345,7 @@ admin/views/federation.vue:
chart-spans:
hour: "每小时"
day: "每天"
blocked-hosts: "拉黑"
desktop/views/pages/welcome.vue:
about: "更多信息..."
timeline: "时间线"
@ -1621,25 +1616,6 @@ deck/deck.user-column.vue:
docs:
edit-this-page-on-github: "发现错误或想要为文档做出贡献?"
edit-this-page-on-github-link: "在GitHub上编辑这个页面。"
api:
entities:
properties: "属性"
endpoints:
params: "参数"
no-params: "没有参数"
res: "回应"
require-credential: "此端点需要身份验证信息。"
require-permission: "此端点需要{permission}权限。"
has-limit: "有一个速率限制。"
duration-limit: "如果您发送请求在{duration}毫秒内多于{max}次,则无法发送更多请求。"
min-interval-limit: "如果自上次请求后未传递{interval}毫秒,则无法发送请求。"
show-src: "您可以查看此端点的源代码。"
show-src-link: "查阅GitHub上的代码"
generated: "该文档由API定义生成。"
props:
name: "名称"
type: "型号"
description: "描述"
dev/views/index.vue:
manage-apps: "管理应用"
dev/views/apps.vue:
@ -1662,3 +1638,254 @@ dev/views/new-app.vue:
authority: "权限"
authority-desc: "只能通过API访问此处请求的功能。"
authority-warning: "您可以在创建应用程序后对其进行更改,但如果您授予不同的权限,则当时关联的所有用户密钥都将失效。"
pages:
new-page: "创建页面"
edit-page: "编辑页面"
read-page: "查看源"
page-created: "页面已创建"
page-updated: "页面已更新"
are-you-sure-delete: "是否删除此页面?"
page-deleted: "该页面已被删除。"
edit-this-page: "编辑此页面"
view-source: "查看源代码"
view-page: "查看页面"
inspector: "检查器"
content: "页面内容"
variables: "变量"
variables-info: "您可以使用变量创建动态页面。在文本中通过<b>{变量名}</b>的写法来嵌入变量值。例如在文本<b>Hello { thing } world!</b>中,如果变量(thing)的值为<b>ai</b>,那么该文本会成为<b>Hello ai world!</b>。"
variables-info2: "因为变量的计算(计算变量值)是从上到下执行的,所以不能在变量中引用下面的变量。例如从上到下依次定义了<b>ABC</b>3个变量那么<b>C</b>中可以引用<b>A</b>或<b>B</b>,但是<b>A</b>无法引用<b>B</b>或<b>C</b>。"
variables-info3: "为了接收来自用户的输入,页面上设有“用户输入”块,在“变量名称”中设置要在其中保存输入值的变量名(变量会自动创建)。您可以使用该变量执行操作以响应用户输入。"
variables-info4: "通过使用函数,您可以将数值计算过程组合成可重用的形式。要创建函数,需要创建一个“函数”类型的变量。你可以将函数设定为槽函数(参数)的格式槽函数的值可作为函数中的变量使用。另外AiScript标准中还有一些函数会将函数作为参数(称为高阶函数)。\n除了已经预先定义的函数外您也可以将它们设置为这些高阶函数的槽函数。"
more-details: "详细说明"
title: "标题"
url: "页面URL"
summary: "页面摘要"
align-center: "居中"
font: "字体"
fontSerif: "衬线字体"
fontSansSerif: "无衬线字体"
set-eye-catching-image: "设置封面图片"
remove-eye-catching-image: "删除封面图片"
choose-block: "添加块"
select-type: "类型选择"
enter-variable-name: "请确定变量名"
the-variable-name-is-already-used: "变量名已使用"
content-blocks: "内容"
input-blocks: "输入"
special-blocks: "特殊"
post-from-post-form: "发布此内容"
posted-from-post-form: "已发布"
blocks:
text: "文本"
textarea: "文本区域"
section: "章节"
image: "图片"
button: "按钮"
if: "如果"
_if:
variable: "变量"
post: "投稿形式"
_post:
text: "内容"
textInput: "文本输入"
_textInput:
name: "变量名"
text: "标题"
default: "默认值"
textareaInput: "多行文本输入"
_textareaInput:
name: "变量名"
text: "标题"
default: "默认值"
numberInput: "数值输入"
_numberInput:
name: "变量名"
text: "标题"
default: "默认值"
switch: "开关"
_switch:
name: "变量名"
text: "标题"
default: "默认值"
counter: "计数器"
_counter:
name: "变量名"
text: "标题"
inc: "增加值"
_button:
text: "标题"
action: "按下按钮时的行为"
_action:
dialog: "显示对话框"
_dialog:
content: "内容"
resetRandom: "随机值重置"
script:
categories:
flow: "控制"
logical: "逻辑运算"
operation: "计算"
comparison: "比较"
random: "随机"
value: "值"
fn: "函数"
text: "文本操作"
convert: "转换"
list: "列表"
blocks:
text: "文本"
multiLineText: "文本 (多行)"
textList: "文本列表"
_textList:
info: "情使用换行符分隔每行"
strLen: "文本长度"
_strLen:
arg1: "文本"
strPick: "字符提取"
_strPick:
arg1: "文本"
arg2: "字符位置"
strReplace: "文本替换"
_strReplace:
arg1: "文本"
arg2: "替换之前"
arg3: "替换之后"
strReverse: "文本反向"
_strReverse:
arg1: "文本"
join: "合并文本"
_join:
arg1: "列表"
arg2: "分隔符"
add: "+ 加"
_add:
arg1: "A"
arg2: "B"
subtract: "- 减"
_subtract:
arg1: "A"
arg2: "B"
multiply: "× 乘"
_multiply:
arg1: "A"
arg2: "B"
divide: "÷ 除"
_divide:
arg1: "A"
arg2: "B"
remind: "÷ 取模"
_remind:
arg1: "A"
arg2: "B"
eq: "A和B相等"
_eq:
arg1: "A"
arg2: "B"
notEq: "A和B不等"
_notEq:
arg1: "A"
arg2: "B"
and: "A和B"
_and:
arg1: "A"
arg2: "B"
or: "A或B"
_or:
arg1: "A"
arg2: "B"
lt: "< A小于B"
_lt:
arg1: "A"
arg2: "B"
gt: "> A大于B"
_gt:
arg1: "A"
arg2: "B"
ltEq: "<= A小于等于B"
_ltEq:
arg1: "A"
arg2: "B"
gtEq: ">= A大于等于B"
_gtEq:
arg1: "A"
arg2: "B"
if: "分支"
_if:
arg1: "如果"
arg2: "的话"
arg3: "否则"
not: "否定"
_not:
arg1: "否定"
random: "随机"
_random:
arg1: "概率"
rannum: "随机"
_rannum:
arg1: "最小"
arg2: "最大"
randomPick: "从列表中随机选择"
_randomPick:
arg1: "列表"
dailyRandom: "随机(每个用户每日)"
_dailyRandom:
arg1: "概率"
dailyRannum: "随机数(每个用户每日)"
_dailyRannum:
arg1: "最小"
arg2: "最大"
dailyRandomPick: "从列表中随机选择(每个用户每日)"
_dailyRandomPick:
arg1: "列表"
seedRandom: "随机 (种子)"
_seedRandom:
arg1: "种子"
arg2: "概率"
seedRannum: "随机数(种子)"
_seedRannum:
arg1: "种子"
arg2: "最小"
arg3: "最大"
seedRandomPick: "从列表中随机选择 (种子)"
_seedRandomPick:
arg1: "种子"
arg2: "列表"
DRPWPM: "从概率列表中随机选择(每用户每天)"
_DRPWPM:
arg1: "文本列表"
pick: "从列表中选择"
_pick:
arg1: "列表"
arg2: "位置"
number: "数值"
stringToNumber: "文本到数字"
_stringToNumber:
arg1: "文本"
numberToString: "数字到文本"
_numberToString:
arg1: "数值"
splitStrByLine: "将文本按行拆分"
_splitStrByLine:
arg1: "文本"
ref: "变量"
fn: "函数"
_fn:
slots: "槽函数"
slots-info: "请使用换行符分隔每个槽函数"
arg1: "输出"
for: "重复"
_for:
arg1: "次数"
arg2: "处理"
typeError: "槽函数{slot}需要传入“{expect}”,但是实际传入为“{actual}”!"
thereIsEmptySlot: "槽函数{slot}为空!"
types:
string: "文本"
number: "数值"
boolean: "布尔值"
array: "列表"
stringArray: "文本列表"
emptySlot: "空白槽函数"
enviromentVariables: "环境变量"
pageVariables: "页面元素"
argVariables: "输入槽函数"

View File

@ -0,0 +1,31 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class Pages1556348509290 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`CREATE TYPE "page_visibility_enum" AS ENUM('public', 'followers', 'specified')`);
await queryRunner.query(`CREATE TABLE "page" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, "title" character varying(256) NOT NULL, "name" character varying(256) NOT NULL, "summary" character varying(256), "alignCenter" boolean NOT NULL, "font" character varying(32) NOT NULL, "userId" character varying(32) NOT NULL, "eyeCatchingImageId" character varying(32), "content" jsonb NOT NULL DEFAULT '[]', "variables" jsonb NOT NULL DEFAULT '[]', "visibility" "page_visibility_enum" NOT NULL, "visibleUserIds" character varying(32) array NOT NULL DEFAULT '{}'::varchar[], CONSTRAINT "PK_742f4117e065c5b6ad21b37ba1f" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_fbb4297c927a9b85e9cefa2eb1" ON "page" ("createdAt") `);
await queryRunner.query(`CREATE INDEX "IDX_af639b066dfbca78b01a920f8a" ON "page" ("updatedAt") `);
await queryRunner.query(`CREATE INDEX "IDX_b82c19c08afb292de4600d99e4" ON "page" ("name") `);
await queryRunner.query(`CREATE INDEX "IDX_ae1d917992dd0c9d9bbdad06c4" ON "page" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_90148bbc2bf0854428786bfc15" ON "page" ("visibleUserIds") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_2133ef8317e4bdb839c0dcbf13" ON "page" ("userId", "name") `);
await queryRunner.query(`ALTER TABLE "page" ADD CONSTRAINT "FK_ae1d917992dd0c9d9bbdad06c4a" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "page" ADD CONSTRAINT "FK_3126dd7c502c9e4d7597ef7ef10" FOREIGN KEY ("eyeCatchingImageId") REFERENCES "drive_file"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "page" DROP CONSTRAINT "FK_3126dd7c502c9e4d7597ef7ef10"`);
await queryRunner.query(`ALTER TABLE "page" DROP CONSTRAINT "FK_ae1d917992dd0c9d9bbdad06c4a"`);
await queryRunner.query(`DROP INDEX "IDX_2133ef8317e4bdb839c0dcbf13"`);
await queryRunner.query(`DROP INDEX "IDX_90148bbc2bf0854428786bfc15"`);
await queryRunner.query(`DROP INDEX "IDX_ae1d917992dd0c9d9bbdad06c4"`);
await queryRunner.query(`DROP INDEX "IDX_b82c19c08afb292de4600d99e4"`);
await queryRunner.query(`DROP INDEX "IDX_af639b066dfbca78b01a920f8a"`);
await queryRunner.query(`DROP INDEX "IDX_fbb4297c927a9b85e9cefa2eb1"`);
await queryRunner.query(`DROP TABLE "page"`);
await queryRunner.query(`DROP TYPE "page_visibility_enum"`);
}
}

View File

@ -0,0 +1,23 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class UserProfile1556746559567 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`UPDATE "user_profile" SET github = FALSE`);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "githubId"`);
await queryRunner.query(`ALTER TABLE "user_profile" ADD COLUMN "githubId" VARCHAR(64)`);
await queryRunner.query(`UPDATE "user_profile" SET discord = FALSE`);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "discordExpiresDate"`);
await queryRunner.query(`ALTER TABLE "user_profile" ADD COLUMN "discordExpiresDate" VARCHAR(64)`);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`UPDATE "user_profile" SET github = FALSE`);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "githubId"`);
await queryRunner.query(`ALTER TABLE "user_profile" ADD COLUMN "githubId" INTEGER`);
await queryRunner.query(`UPDATE "user_profile" SET discord = FALSE`);
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "discordExpiresDate"`);
await queryRunner.query(`ALTER TABLE "user_profile" ADD COLUMN "discordExpiresDate" INTEGER`);
}
}

View File

@ -0,0 +1,13 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class PinnedUsers1557476068003 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "meta" ADD "pinnedUsers" character varying(256) array NOT NULL DEFAULT '{}'::varchar[]`);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "pinnedUsers"`);
}
}

View File

@ -0,0 +1,16 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class AddSomeUrls1557761316509 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "meta" ADD "ToSUrl" character varying(512)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "repositoryUrl" character varying(512) NOT NULL DEFAULT 'https://github.com/syuilo/misskey'`);
await queryRunner.query(`ALTER TABLE "meta" ADD "feedbackUrl" character varying(512) DEFAULT 'https://github.com/syuilo/misskey/issues/new'`);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "feedbackUrl"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "repositoryUrl"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "ToSUrl"`);
}
}

View File

@ -0,0 +1,31 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class ObjectStorageSetting1557932705754 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "meta" ADD "useObjectStorage" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`ALTER TABLE "meta" ADD "objectStorageBucket" character varying(512)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "objectStoragePrefix" character varying(512)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "objectStorageBaseUrl" character varying(512)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "objectStorageEndpoint" character varying(512)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "objectStorageRegion" character varying(512)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "objectStorageAccessKey" character varying(512)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "objectStorageSecretKey" character varying(512)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "objectStoragePort" integer`);
await queryRunner.query(`ALTER TABLE "meta" ADD "objectStorageUseSSL" boolean NOT NULL DEFAULT true`);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageUseSSL"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStoragePort"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageSecretKey"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageAccessKey"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageRegion"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageEndpoint"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageBaseUrl"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStoragePrefix"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageBucket"`);
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "useObjectStorage"`);
}
}

View File

@ -1,7 +1,7 @@
{
"name": "misskey",
"author": "syuilo <i@syuilo.com>",
"version": "11.2.2",
"version": "11.14.0",
"codename": "daybreak",
"repository": {
"type": "git",
@ -12,6 +12,8 @@
"scripts": {
"start": "node ./index.js",
"init": "node ./built/init.js",
"ormconfig": "node ./built/ormconfig.js",
"migrate": "npm run ormconfig && ts-node ./node_modules/typeorm/cli.js migration:run",
"build": "webpack && gulp build",
"webpack": "webpack",
"watch": "webpack --watch",
@ -23,20 +25,19 @@
"format": "gulp format"
},
"dependencies": {
"@elastic/elasticsearch": "7.0.0-rc.2",
"@fortawesome/fontawesome-svg-core": "1.2.15",
"@fortawesome/free-brands-svg-icons": "5.7.2",
"@fortawesome/free-regular-svg-icons": "5.7.2",
"@fortawesome/free-solid-svg-icons": "5.7.2",
"@fortawesome/vue-fontawesome": "0.1.5",
"@koa/cors": "2.2.3",
"@prezzemolo/rap": "0.1.2",
"@prezzemolo/zip": "0.0.3",
"@types/bcryptjs": "2.4.2",
"@types/bull": "3.5.11",
"@types/dateformat": "3.0.0",
"@types/deep-equal": "1.0.1",
"@types/double-ended-queue": "2.1.0",
"@types/elasticsearch": "5.0.32",
"@types/file-type": "10.9.1",
"@types/gulp": "4.0.6",
"@types/gulp-mocha": "0.0.32",
@ -64,8 +65,8 @@
"@types/lolex": "3.1.1",
"@types/minio": "7.0.1",
"@types/mocha": "5.2.6",
"@types/node": "11.13.4",
"@types/nodemailer": "4.6.7",
"@types/node": "11.13.8",
"@types/nodemailer": "4.6.8",
"@types/nprogress": "0.0.29",
"@types/oauth": "0.9.1",
"@types/parse5": "5.0.0",
@ -78,9 +79,10 @@
"@types/redis": "2.8.12",
"@types/rename": "1.0.1",
"@types/request": "2.48.1",
"@types/request-promise-native": "1.0.15",
"@types/request-promise-native": "1.0.16",
"@types/request-stats": "3.0.0",
"@types/rimraf": "2.0.2",
"@types/seedrandom": "2.4.28",
"@types/sharp": "0.22.1",
"@types/showdown": "1.9.2",
"@types/speakeasy": "2.0.4",
@ -89,18 +91,18 @@
"@types/tmp": "0.1.0",
"@types/uuid": "3.4.4",
"@types/web-push": "3.3.0",
"@types/webpack": "4.4.27",
"@types/webpack": "4.4.29",
"@types/webpack-stream": "3.2.10",
"@types/websocket": "0.0.40",
"@types/ws": "6.0.1",
"animejs": "3.0.1",
"apexcharts": "3.6.8",
"apexcharts": "3.6.11",
"autobind-decorator": "2.4.0",
"autosize": "4.0.2",
"autwh": "0.1.0",
"bcryptjs": "2.4.3",
"bootstrap-vue": "2.0.0-rc.13",
"bull": "3.7.0",
"bull": "3.9.1",
"cafy": "15.1.1",
"chai": "4.2.0",
"chalk": "2.4.2",
@ -112,17 +114,16 @@
"cssnano": "4.1.10",
"dateformat": "3.0.3",
"deep-equal": "1.0.1",
"diskusage": "1.1.0",
"diskusage": "1.1.1",
"double-ended-queue": "2.1.0-0",
"elasticsearch": "15.4.1",
"emojilib": "2.4.0",
"eslint": "5.16.0",
"eslint-plugin-vue": "5.2.2",
"eventemitter3": "3.1.0",
"eventemitter3": "3.1.2",
"feed": "2.0.4",
"file-type": "10.11.0",
"fuckadblock": "3.2.1",
"gulp": "4.0.0",
"gulp": "4.0.2",
"gulp-cssnano": "2.1.3",
"gulp-imagemin": "5.0.3",
"gulp-mocha": "6.0.0",
@ -141,7 +142,7 @@
"is-root": "2.1.0",
"is-svg": "4.1.0",
"js-yaml": "3.13.1",
"jsdom": "14.1.0",
"jsdom": "15.1.0",
"json5": "2.1.0",
"json5-loader": "2.0.0",
"katex": "0.10.1",
@ -161,20 +162,20 @@
"loader-utils": "1.2.3",
"lolex": "3.1.0",
"lookup-dns-cache": "2.1.0",
"minio": "7.0.6",
"mocha": "6.1.3",
"minio": "7.0.8",
"mocha": "6.1.4",
"moji": "0.5.1",
"moment": "2.24.0",
"ms": "2.1.1",
"nested-property": "0.0.7",
"node-fetch": "2.3.0",
"node-fetch": "2.5.0",
"nodemailer": "6.1.1",
"nprogress": "0.2.0",
"object-assign-deep": "0.4.0",
"os-utils": "0.0.14",
"parse5": "5.1.0",
"parsimmon": "1.12.0",
"pg": "7.10.0",
"pg": "7.11.0",
"portscanner": "2.2.0",
"postcss-loader": "3.0.0",
"prismjs": "1.16.0",
@ -201,7 +202,8 @@
"rimraf": "2.6.3",
"rndstr": "1.0.0",
"s-age": "1.1.2",
"sharp": "0.22.0",
"seedrandom": "3.0.1",
"sharp": "0.22.1",
"showdown": "1.9.0",
"showdown-highlightjs-extension": "0.1.2",
"speakeasy": "2.0.0",
@ -210,7 +212,7 @@
"stylus": "0.54.5",
"stylus-loader": "3.0.2",
"summaly": "2.2.0",
"systeminformation": "4.1.5",
"systeminformation": "4.1.6",
"syuilo-password-strength": "0.0.1",
"terser-webpack-plugin": "1.2.3",
"textarea-caret": "3.1.0",
@ -234,8 +236,8 @@
"vue-color": "2.7.0",
"vue-content-loading": "1.6.0",
"vue-cropperjs": "3.0.0",
"vue-i18n": "8.10.0",
"vue-js-modal": "1.3.28",
"vue-i18n": "8.11.2",
"vue-js-modal": "1.3.31",
"vue-json-pretty": "1.6.0",
"vue-loader": "15.7.0",
"vue-marquee-text-component": "1.1.1",
@ -247,13 +249,13 @@
"vue-template-compiler": "2.6.10",
"vuedraggable": "2.20.0",
"vuewordcloud": "18.7.11",
"vuex": "3.1.0",
"vuex": "3.1.1",
"vuex-persistedstate": "2.5.4",
"web-push": "3.3.3",
"webpack": "4.30.0",
"webpack-cli": "3.3.0",
"web-push": "3.3.4",
"webpack": "4.31.0",
"webpack-cli": "3.3.2",
"websocket": "1.0.28",
"ws": "6.2.1",
"ws": "7.0.0",
"xev": "2.0.1"
}
}

View File

@ -27,7 +27,7 @@ function greet() {
console.log(' ' + chalk.gray(v) + (' |___|\n'.substr(v.length)));
//#endregion
console.log(' Misskey is maintained by @syuilo, @AyaMorisawa, @mei23, and @acid-chicken.');
console.log(' Misskey is maintained by @syuilo, @AyaMorisawa, @mei23, @acid-chicken, and @rinsuki.');
console.log(chalk.keyword('orange')(' If you like Misskey, please donate to support development. https://www.patreon.com/syuilo'));
console.log('');

View File

@ -9,6 +9,9 @@
<ui-textarea v-model="announcement.text">
<span>{{ $t('text') }}</span>
</ui-textarea>
<ui-input v-model="announcement.image">
<span>{{ $t('image-url') }}</span>
</ui-input>
<ui-horizon-group class="fit-bottom">
<ui-button @click="save()"><fa :icon="['far', 'save']"/> {{ $t('save') }}</ui-button>
<ui-button @click="remove(i)"><fa :icon="['far', 'trash-alt']"/> {{ $t('remove') }}</ui-button>
@ -43,7 +46,8 @@ export default Vue.extend({
add() {
this.announcements.unshift({
title: '',
text: ''
text: '',
image: null
});
},

View File

@ -54,7 +54,6 @@
<span>{{ $t('latest-request-received-at') }}</span>
<template #prefix><fa :icon="faInbox"/></template>
</ui-input>
<ui-switch v-model="instance.isBlocked" @change="updateInstance()">{{ $t('block') }}</ui-switch>
<ui-switch v-model="instance.isMarkedAsClosed" @change="updateInstance()">{{ $t('marked-as-closed') }}</ui-switch>
<details>
<summary>{{ $t('charts') }}</summary>
@ -79,6 +78,10 @@
</ui-horizon-group>
<div ref="chart"></div>
</details>
<details>
<summary>{{ $t('delete-all-files') }}</summary>
<ui-button @click="deleteAllFiles()" style="margin-top: 16px;"><fa :icon="faTrashAlt"/> {{ $t('delete-all-files') }}</ui-button>
</details>
<details>
<summary>{{ $t('remove-all-following') }}</summary>
<ui-button @click="removeAllFollowing()" style="margin-top: 16px;"><fa :icon="faMinusCircle"/> {{ $t('remove-all-following') }}</ui-button>
@ -130,7 +133,7 @@
<span>{{ $t('status') }}</span>
</header>
<div v-for="instance in instances" :style="{ opacity: instance.isNotResponding ? 0.5 : 1 }">
<a @click.prevent="showInstance(instance.host)" target="_blank" :href="`https://${instance.host}`" :style="{ textDecoration: instance.isMarkedAsClosed ? 'line-through' : 'none' }">{{ instance.host }}</a>
<a @click.prevent="showInstance(instance.host)" rel="nofollow noopener" target="_blank" :href="`https://${instance.host}`" :style="{ textDecoration: instance.isMarkedAsClosed ? 'line-through' : 'none' }">{{ instance.host }}</a>
<span>{{ instance.notesCount | number }}</span>
<span>{{ instance.usersCount | number }}</span>
<span>{{ instance.followingCount | number }}</span>
@ -142,6 +145,16 @@
<ui-info v-if="instances.length == limit">{{ $t('result-is-truncated', { n: limit }) }}</ui-info>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="faBan"/> {{ $t('blocked-hosts') }}</template>
<section class="fit-top">
<ui-textarea v-model="blockedHosts">
<template #desc>{{ $t('blocked-hosts-info') }}</template>
</ui-textarea>
<ui-button @click="saveBlockedHosts">{{ $t('save') }}</ui-button>
</section>
</ui-card>
</div>
</template>
@ -149,7 +162,7 @@
import Vue from 'vue';
import i18n from '../../i18n';
import { faPaperPlane } from '@fortawesome/free-regular-svg-icons';
import { faGlobe, faTerminal, faSearch, faMinusCircle, faServer, faCrosshairs, faEnvelopeOpenText, faUsers, faCaretDown, faCaretUp, faTrafficLight, faInbox } from '@fortawesome/free-solid-svg-icons';
import { faTrashAlt, faBan, faGlobe, faTerminal, faSearch, faMinusCircle, faServer, faCrosshairs, faEnvelopeOpenText, faUsers, faCaretDown, faCaretUp, faTrafficLight, faInbox } from '@fortawesome/free-solid-svg-icons';
import ApexCharts from 'apexcharts';
import * as tinycolor from 'tinycolor2';
@ -176,7 +189,8 @@ export default Vue.extend({
chartSrc: 'requests',
chartSpan: 'hour',
chartInstance: null,
faGlobe, faTerminal, faSearch, faMinusCircle, faServer, faCrosshairs, faEnvelopeOpenText, faUsers, faCaretDown, faCaretUp, faPaperPlane, faTrafficLight, faInbox
blockedHosts: '',
faTrashAlt, faBan, faGlobe, faTerminal, faSearch, faMinusCircle, faServer, faCrosshairs, faEnvelopeOpenText, faUsers, faCaretDown, faCaretUp, faPaperPlane, faTrafficLight, faInbox
};
},
@ -246,6 +260,10 @@ export default Vue.extend({
mounted() {
this.fetchInstances();
this.$root.getMeta().then(meta => {
this.blockedHosts = meta.blockedHosts.join('\n');
});
},
beforeDestroy() {
@ -293,6 +311,17 @@ export default Vue.extend({
});
},
deleteAllFiles() {
this.$root.api('admin/federation/delete-all-files', {
host: this.instance.host
}).then(() => {
this.$root.dialog({
type: 'success',
splash: true
});
});
},
updateInstance() {
this.$root.api('admin/federation/update-instance', {
host: this.instance.host,
@ -477,6 +506,22 @@ export default Vue.extend({
}]
};
},
saveBlockedHosts() {
this.$root.api('admin/update-meta', {
blockedHosts: this.blockedHosts.split('\n')
}).then(() => {
this.$root.dialog({
type: 'success',
text: this.$t('saved')
});
}).catch(e => {
this.$root.dialog({
type: 'error',
text: e
});
});
}
}
});
</script>

View File

@ -1,41 +0,0 @@
<template>
<div>
<ui-card>
<template #title>{{ $t('hided-tags') }}</template>
<section>
<textarea class="jdnqwkzlnxcfftthoybjxrebyolvoucw" v-model="hiddenTags"></textarea>
<ui-button @click="save">{{ $t('save') }}</ui-button>
</section>
</ui-card>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../i18n';
export default Vue.extend({
i18n: i18n('admin/views/hashtags.vue'),
data() {
return {
hiddenTags: '',
};
},
created() {
this.$root.getMeta().then(meta => {
this.hiddenTags = meta.hiddenTags.join('\n');
});
},
methods: {
save() {
this.$root.api('admin/update-meta', {
hiddenTags: this.hiddenTags.split('\n')
}).then(() => {
//this.$root.os.apis.dialog({ text: `Saved` });
}).catch(e => {
//this.$root.os.apis.dialog({ text: `Failed ${e}` });
});
}
}
});
</script>

View File

@ -28,7 +28,6 @@
<li @click="nav('federation')" :class="{ active: page == 'federation' }"><fa :icon="faGlobe" fixed-width/>{{ $t('federation') }}</li>
<li @click="nav('emoji')" :class="{ active: page == 'emoji' }"><fa :icon="faGrin" fixed-width/>{{ $t('emoji') }}</li>
<li @click="nav('announcements')" :class="{ active: page == 'announcements' }"><fa icon="broadcast-tower" fixed-width/>{{ $t('announcements') }}</li>
<li @click="nav('hashtags')" :class="{ active: page == 'hashtags' }"><fa icon="hashtag" fixed-width/>{{ $t('hashtags') }}</li>
<li @click="nav('abuse')" :class="{ active: page == 'abuse' }"><fa :icon="faExclamationCircle" fixed-width/>{{ $t('abuse') }}</li>
</ul>
<div class="back-to-misskey">
@ -48,7 +47,6 @@
<div v-if="page == 'users'"><x-users/></div>
<div v-if="page == 'emoji'"><x-emoji/></div>
<div v-if="page == 'announcements'"><x-announcements/></div>
<div v-if="page == 'hashtags'"><x-hashtags/></div>
<div v-if="page == 'drive'"><x-drive/></div>
<div v-if="page == 'federation'"><x-federation/></div>
<div v-if="page == 'abuse'"><x-abuse/></div>
@ -68,7 +66,6 @@ import XLogs from "./logs.vue";
import XModerators from "./moderators.vue";
import XEmoji from "./emoji.vue";
import XAnnouncements from "./announcements.vue";
import XHashtags from "./hashtags.vue";
import XUsers from "./users.vue";
import XDrive from "./drive.vue";
import XAbuse from "./abuse.vue";
@ -91,7 +88,6 @@ export default Vue.extend({
XModerators,
XEmoji,
XAnnouncements,
XHashtags,
XUsers,
XDrive,
XAbuse,

View File

@ -2,7 +2,7 @@
<div>
<ui-card>
<template #title><fa icon="cog"/> {{ $t('instance') }}</template>
<section class="fit-top fit-bottom">
<section class="fit-top">
<ui-input :value="host" readonly>{{ $t('host') }}</ui-input>
<ui-input v-model="name">{{ $t('instance-name') }}</ui-input>
<ui-textarea v-model="description">{{ $t('instance-description') }}</ui-textarea>
@ -10,124 +10,229 @@
<ui-input v-model="mascotImageUrl"><template #icon><fa icon="link"/></template>{{ $t('logo-url') }}</ui-input>
<ui-input v-model="bannerUrl"><template #icon><fa icon="link"/></template>{{ $t('banner-url') }}</ui-input>
<ui-input v-model="errorImageUrl"><template #icon><fa icon="link"/></template>{{ $t('error-image-url') }}</ui-input>
<ui-input v-model="ToSUrl"><template #icon><fa icon="link"/></template>{{ $t('tos-url') }}</ui-input>
<ui-input v-model="languages"><template #icon><fa icon="language"/></template>{{ $t('languages') }}<template #desc>{{ $t('languages-desc') }}</template></ui-input>
<details>
<summary>{{ $t('advanced-config') }}</summary>
<ui-input v-model="repositoryUrl"><template #icon><fa icon="link"/></template>{{ $t('repository-url') }}</ui-input>
<ui-input v-model="feedbackUrl"><template #icon><fa icon="link"/></template>{{ $t('feedback-url') }}</ui-input>
</details>
</section>
<section class="fit-bottom">
<header><fa :icon="faHeadset"/> {{ $t('maintainer-config') }}</header>
<ui-input v-model="maintainerName">{{ $t('maintainer-name') }}</ui-input>
<ui-input v-model="maintainerEmail" type="email"><template #icon><fa :icon="farEnvelope"/></template>{{ $t('maintainer-email') }}</ui-input>
</section>
<section>
<ui-switch v-model="disableRegistration">{{ $t('disable-registration') }}</ui-switch>
<ui-button v-if="disableRegistration" @click="invite">{{ $t('invite') }}</ui-button>
</section>
<section>
<ui-button @click="updateMeta"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="faPencilAlt"/> {{ $t('note-and-tl') }}</template>
<section class="fit-top fit-bottom">
<ui-input v-model="maxNoteTextLength">{{ $t('max-note-text-length') }}</ui-input>
</section>
<section>
<ui-switch v-model="disableRegistration">{{ $t('disable-registration') }}</ui-switch>
<ui-switch v-model="disableLocalTimeline">{{ $t('disable-local-timeline') }}</ui-switch>
<ui-switch v-model="disableGlobalTimeline">{{ $t('disable-global-timeline') }}</ui-switch>
<ui-info>{{ $t('disabling-timelines-info') }}</ui-info>
</section>
<section>
<ui-switch v-model="enableEmojiReaction">{{ $t('enable-emoji-reaction') }}</ui-switch>
<ui-switch v-model="useStarForReactionFallback">{{ $t('use-star-for-reaction-fallback') }}</ui-switch>
</section>
<section class="fit-bottom">
<header><fa icon="cloud"/> {{ $t('drive-config') }}</header>
<section>
<ui-button @click="updateMeta"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title><fa icon="cloud"/> {{ $t('drive-config') }}</template>
<section>
<ui-switch v-model="useObjectStorage">{{ $t('use-object-storage') }}</ui-switch>
<template v-if="useObjectStorage">
<ui-info>
<i18n path="object-storage-s3-info">
<a href="https://docs.aws.amazon.com/general/latest/gr/rande.html" target="_blank">{{ $t('object-storage-s3-info-here') }}</a>
</i18n>
</ui-info>
<ui-info>{{ $t('object-storage-gcs-info') }}</ui-info>
<ui-input v-model="objectStorageBaseUrl" :disabled="!useObjectStorage">{{ $t('object-storage-base-url') }}</ui-input>
<ui-horizon-group inputs>
<ui-input v-model="objectStorageBucket" :disabled="!useObjectStorage">{{ $t('object-storage-bucket') }}</ui-input>
<ui-input v-model="objectStoragePrefix" :disabled="!useObjectStorage">{{ $t('object-storage-prefix') }}</ui-input>
</ui-horizon-group>
<ui-input v-model="objectStorageEndpoint" :disabled="!useObjectStorage">{{ $t('object-storage-endpoint') }}</ui-input>
<ui-horizon-group inputs>
<ui-input v-model="objectStorageRegion" :disabled="!useObjectStorage">{{ $t('object-storage-region') }}</ui-input>
<ui-input v-model="objectStoragePort" type="number" :disabled="!useObjectStorage">{{ $t('object-storage-port') }}</ui-input>
</ui-horizon-group>
<ui-horizon-group inputs>
<ui-input v-model="objectStorageAccessKey" :disabled="!useObjectStorage"><template #icon><fa icon="key"/></template>{{ $t('object-storage-access-key') }}</ui-input>
<ui-input v-model="objectStorageSecretKey" :disabled="!useObjectStorage"><template #icon><fa icon="key"/></template>{{ $t('object-storage-secret-key') }}</ui-input>
</ui-horizon-group>
<ui-switch v-model="objectStorageUseSSL" :disabled="!useObjectStorage">{{ $t('object-storage-use-ssl') }}</ui-switch>
</template>
</section>
<section>
<ui-switch v-model="cacheRemoteFiles">{{ $t('cache-remote-files') }}<template #desc>{{ $t('cache-remote-files-desc') }}</template></ui-switch>
</section>
<section class="fit-top fit-bottom">
<ui-input v-model="localDriveCapacityMb" type="number">{{ $t('local-drive-capacity-mb') }}<template #suffix>MB</template><template #desc>{{ $t('mb') }}</template></ui-input>
<ui-input v-model="remoteDriveCapacityMb" type="number" :disabled="!cacheRemoteFiles">{{ $t('remote-drive-capacity-mb') }}<template #suffix>MB</template><template #desc>{{ $t('mb') }}</template></ui-input>
</section>
<section class="fit-bottom">
<header><fa :icon="faShieldAlt"/> {{ $t('recaptcha-config') }}</header>
<ui-switch v-model="enableRecaptcha">{{ $t('enable-recaptcha') }}</ui-switch>
<ui-info>{{ $t('recaptcha-info') }}</ui-info>
<ui-horizon-group inputs>
<ui-input v-model="recaptchaSiteKey" :disabled="!enableRecaptcha"><template #icon><fa icon="key"/></template>{{ $t('recaptcha-site-key') }}</ui-input>
<ui-input v-model="recaptchaSecretKey" :disabled="!enableRecaptcha"><template #icon><fa icon="key"/></template>{{ $t('recaptcha-secret-key') }}</ui-input>
</ui-horizon-group>
</section>
<section>
<header><fa :icon="faGhost"/> {{ $t('proxy-account-config') }}</header>
<ui-button @click="updateMeta"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="faThumbtack"/> {{ $t('pinned-users') }}</template>
<section class="fit-top">
<ui-textarea v-model="pinnedUsers">
<template #desc>{{ $t('pinned-users-info') }}</template>
</ui-textarea>
<ui-button @click="updateMeta"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="faGhost"/> {{ $t('proxy-account-config') }}</template>
<section>
<ui-info>{{ $t('proxy-account-info') }}</ui-info>
<ui-input v-model="proxyAccount"><template #prefix>@</template>{{ $t('proxy-account-username') }}<template #desc>{{ $t('proxy-account-username-desc') }}</template></ui-input>
<ui-info warn>{{ $t('proxy-account-warn') }}</ui-info>
</section>
<section>
<header><fa :icon="farEnvelope"/> {{ $t('email-config') }}</header>
<ui-button @click="updateMeta"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="farEnvelope"/> {{ $t('email-config') }}</template>
<section>
<ui-switch v-model="enableEmail">{{ $t('enable-email') }}<template #desc>{{ $t('email-config-info') }}</template></ui-switch>
<ui-input v-model="email" type="email" :disabled="!enableEmail">{{ $t('email') }}</ui-input>
<ui-horizon-group inputs>
<ui-input v-model="smtpHost" :disabled="!enableEmail">{{ $t('smtp-host') }}</ui-input>
<ui-input v-model="smtpPort" type="number" :disabled="!enableEmail">{{ $t('smtp-port') }}</ui-input>
</ui-horizon-group>
<ui-switch v-model="smtpAuth">{{ $t('smtp-auth') }}</ui-switch>
<ui-horizon-group inputs>
<ui-input v-model="smtpUser" :disabled="!enableEmail || !smtpAuth">{{ $t('smtp-user') }}</ui-input>
<ui-input v-model="smtpPass" type="password" :withPasswordToggle="true" :disabled="!enableEmail || !smtpAuth">{{ $t('smtp-pass') }}</ui-input>
</ui-horizon-group>
<ui-switch v-model="smtpSecure" :disabled="!enableEmail">{{ $t('smtp-secure') }}<template #desc>{{ $t('smtp-secure-info') }}</template></ui-switch>
<template v-if="enableEmail">
<ui-input v-model="email" type="email" :disabled="!enableEmail">{{ $t('email') }}</ui-input>
<ui-horizon-group inputs>
<ui-input v-model="smtpHost" :disabled="!enableEmail">{{ $t('smtp-host') }}</ui-input>
<ui-input v-model="smtpPort" type="number" :disabled="!enableEmail">{{ $t('smtp-port') }}</ui-input>
</ui-horizon-group>
<ui-switch v-model="smtpAuth">{{ $t('smtp-auth') }}</ui-switch>
<ui-horizon-group inputs>
<ui-input v-model="smtpUser" :disabled="!enableEmail || !smtpAuth">{{ $t('smtp-user') }}</ui-input>
<ui-input v-model="smtpPass" type="password" :with-password-toggle="true" :disabled="!enableEmail || !smtpAuth">{{ $t('smtp-pass') }}</ui-input>
</ui-horizon-group>
<ui-switch v-model="smtpSecure" :disabled="!enableEmail">{{ $t('smtp-secure') }}<template #desc>{{ $t('smtp-secure-info') }}</template></ui-switch>
</template>
</section>
<section>
<header><fa :icon="faBolt"/> {{ $t('serviceworker-config') }}</header>
<ui-button @click="updateMeta"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="faBolt"/> {{ $t('serviceworker-config') }}</template>
<section>
<ui-switch v-model="enableServiceWorker">{{ $t('enable-serviceworker') }}<template #desc>{{ $t('serviceworker-info') }}</template></ui-switch>
<ui-info>{{ $t('vapid-info') }}<br><code>npm i web-push -g<br>web-push generate-vapid-keys</code></ui-info>
<ui-horizon-group inputs class="fit-bottom">
<ui-input v-model="swPublicKey" :disabled="!enableServiceWorker"><template #icon><fa icon="key"/></template>{{ $t('vapid-publickey') }}</ui-input>
<ui-input v-model="swPrivateKey" :disabled="!enableServiceWorker"><template #icon><fa icon="key"/></template>{{ $t('vapid-privatekey') }}</ui-input>
</ui-horizon-group>
<template v-if="enableServiceWorker">
<ui-info>{{ $t('vapid-info') }}<br><code>npm i web-push -g<br>web-push generate-vapid-keys</code></ui-info>
<ui-horizon-group inputs class="fit-bottom">
<ui-input v-model="swPublicKey" :disabled="!enableServiceWorker"><template #icon><fa icon="key"/></template>{{ $t('vapid-publickey') }}</ui-input>
<ui-input v-model="swPrivateKey" :disabled="!enableServiceWorker"><template #icon><fa icon="key"/></template>{{ $t('vapid-privatekey') }}</ui-input>
</ui-horizon-group>
</template>
</section>
<section>
<header>summaly Proxy</header>
<ui-input v-model="summalyProxy">URL</ui-input>
</section>
<section>
<ui-button @click="updateMeta">{{ $t('save') }}</ui-button>
<ui-button @click="updateMeta"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title>{{ $t('invite') }}</template>
<template #title><fa :icon="faShieldAlt"/> {{ $t('recaptcha-config') }}</template>
<section :class="enableRecaptcha ? 'fit-bottom' : ''">
<ui-switch v-model="enableRecaptcha">{{ $t('enable-recaptcha') }}</ui-switch>
<template v-if="enableRecaptcha">
<ui-info>{{ $t('recaptcha-info') }}</ui-info>
<ui-horizon-group inputs>
<ui-input v-model="recaptchaSiteKey" :disabled="!enableRecaptcha"><template #icon><fa icon="key"/></template>{{ $t('recaptcha-site-key') }}</ui-input>
<ui-input v-model="recaptchaSecretKey" :disabled="!enableRecaptcha"><template #icon><fa icon="key"/></template>{{ $t('recaptcha-secret-key') }}</ui-input>
</ui-horizon-group>
</template>
</section>
<section>
<ui-button @click="invite">{{ $t('invite') }}</ui-button>
<p v-if="inviteCode">Code: <code>{{ inviteCode }}</code></p>
<ui-button @click="updateMeta"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="['fab', 'twitter']"/> {{ $t('twitter-integration-config') }}</template>
<template #title><fa :icon="faShieldAlt"/> {{ $t('external-service-integration-config') }}</template>
<section>
<header><fa :icon="['fab', 'twitter']"/> {{ $t('twitter-integration-config') }}</header>
<ui-switch v-model="enableTwitterIntegration">{{ $t('enable-twitter-integration') }}</ui-switch>
<ui-horizon-group>
<ui-input v-model="twitterConsumerKey" :disabled="!enableTwitterIntegration"><template #icon><fa icon="key"/></template>{{ $t('twitter-integration-consumer-key') }}</ui-input>
<ui-input v-model="twitterConsumerSecret" :disabled="!enableTwitterIntegration"><template #icon><fa icon="key"/></template>{{ $t('twitter-integration-consumer-secret') }}</ui-input>
</ui-horizon-group>
<ui-info>{{ $t('twitter-integration-info', { url: `${url}/api/tw/cb` }) }}</ui-info>
<ui-button @click="updateMeta">{{ $t('save') }}</ui-button>
<template v-if="enableTwitterIntegration">
<ui-horizon-group>
<ui-input v-model="twitterConsumerKey" :disabled="!enableTwitterIntegration"><template #icon><fa icon="key"/></template>{{ $t('twitter-integration-consumer-key') }}</ui-input>
<ui-input v-model="twitterConsumerSecret" :disabled="!enableTwitterIntegration"><template #icon><fa icon="key"/></template>{{ $t('twitter-integration-consumer-secret') }}</ui-input>
</ui-horizon-group>
<ui-info>{{ $t('twitter-integration-info', { url: `${url}/api/tw/cb` }) }}</ui-info>
</template>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="['fab', 'github']"/> {{ $t('github-integration-config') }}</template>
<section>
<header><fa :icon="['fab', 'github']"/> {{ $t('github-integration-config') }}</header>
<ui-switch v-model="enableGithubIntegration">{{ $t('enable-github-integration') }}</ui-switch>
<ui-horizon-group>
<ui-input v-model="githubClientId" :disabled="!enableGithubIntegration"><template #icon><fa icon="key"/></template>{{ $t('github-integration-client-id') }}</ui-input>
<ui-input v-model="githubClientSecret" :disabled="!enableGithubIntegration"><template #icon><fa icon="key"/></template>{{ $t('github-integration-client-secret') }}</ui-input>
</ui-horizon-group>
<ui-info>{{ $t('github-integration-info', { url: `${url}/api/gh/cb` }) }}</ui-info>
<ui-button @click="updateMeta">{{ $t('save') }}</ui-button>
<template v-if="enableGithubIntegration">
<ui-horizon-group>
<ui-input v-model="githubClientId" :disabled="!enableGithubIntegration"><template #icon><fa icon="key"/></template>{{ $t('github-integration-client-id') }}</ui-input>
<ui-input v-model="githubClientSecret" :disabled="!enableGithubIntegration"><template #icon><fa icon="key"/></template>{{ $t('github-integration-client-secret') }}</ui-input>
</ui-horizon-group>
<ui-info>{{ $t('github-integration-info', { url: `${url}/api/gh/cb` }) }}</ui-info>
</template>
</section>
<section>
<header><fa :icon="['fab', 'discord']"/> {{ $t('discord-integration-config') }}</header>
<ui-switch v-model="enableDiscordIntegration">{{ $t('enable-discord-integration') }}</ui-switch>
<template v-if="enableDiscordIntegration">
<ui-horizon-group>
<ui-input v-model="discordClientId" :disabled="!enableDiscordIntegration"><template #icon><fa icon="key"/></template>{{ $t('discord-integration-client-id') }}</ui-input>
<ui-input v-model="discordClientSecret" :disabled="!enableDiscordIntegration"><template #icon><fa icon="key"/></template>{{ $t('discord-integration-client-secret') }}</ui-input>
</ui-horizon-group>
<ui-info>{{ $t('discord-integration-info', { url: `${url}/api/dc/cb` }) }}</ui-info>
</template>
</section>
<section>
<ui-button @click="updateMeta"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title><fa :icon="['fab', 'discord']"/> {{ $t('discord-integration-config') }}</template>
<section>
<ui-switch v-model="enableDiscordIntegration">{{ $t('enable-discord-integration') }}</ui-switch>
<ui-horizon-group>
<ui-input v-model="discordClientId" :disabled="!enableDiscordIntegration"><template #icon><fa icon="key"/></template>{{ $t('discord-integration-client-id') }}</ui-input>
<ui-input v-model="discordClientSecret" :disabled="!enableDiscordIntegration"><template #icon><fa icon="key"/></template>{{ $t('discord-integration-client-secret') }}</ui-input>
</ui-horizon-group>
<ui-info>{{ $t('discord-integration-info', { url: `${url}/api/dc/cb` }) }}</ui-info>
<ui-button @click="updateMeta">{{ $t('save') }}</ui-button>
</section>
</ui-card>
<details>
<summary style="color:var(--text);">{{ $t('advanced-config') }}</summary>
<ui-card>
<template #title><fa :icon="faHashtag"/> {{ $t('hidden-tags') }}</template>
<section class="fit-top">
<ui-textarea v-model="hiddenTags">
<template #desc>{{ $t('hidden-tags-info') }}</template>
</ui-textarea>
<ui-button @click="updateMeta"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</section>
</ui-card>
<ui-card>
<template #title>summaly Proxy</template>
<section class="fit-top fit-bottom">
<ui-input v-model="summalyProxy">URL</ui-input>
</section>
<section>
<ui-button @click="updateMeta"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</section>
</ui-card>
</details>
</div>
</template>
@ -136,8 +241,8 @@ import Vue from 'vue';
import i18n from '../../i18n';
import { url, host } from '../../config';
import { toUnicode } from 'punycode';
import { faHeadset, faShieldAlt, faGhost, faUserPlus, faBolt } from '@fortawesome/free-solid-svg-icons';
import { faEnvelope as farEnvelope } from '@fortawesome/free-regular-svg-icons';
import { faHeadset, faShieldAlt, faGhost, faUserPlus, faBolt, faThumbtack, faPencilAlt, faHashtag } from '@fortawesome/free-solid-svg-icons';
import { faEnvelope as farEnvelope, faSave } from '@fortawesome/free-regular-svg-icons';
export default Vue.extend({
i18n: i18n('admin/views/instance.vue'),
@ -148,6 +253,9 @@ export default Vue.extend({
host: toUnicode(host),
maintainerName: null,
maintainerEmail: null,
ToSUrl: null,
repositoryUrl: "https://github.com/syuilo/misskey",
feedbackUrl: null,
disableRegistration: false,
disableLocalTimeline: false,
disableGlobalTimeline: false,
@ -177,7 +285,6 @@ export default Vue.extend({
discordClientId: null,
discordClientSecret: null,
proxyAccount: null,
inviteCode: null,
summalyProxy: null,
enableEmail: false,
email: null,
@ -190,7 +297,19 @@ export default Vue.extend({
enableServiceWorker: false,
swPublicKey: null,
swPrivateKey: null,
faHeadset, faShieldAlt, faGhost, faUserPlus, farEnvelope, faBolt
pinnedUsers: '',
hiddenTags: '',
useObjectStorage: false,
objectStorageBaseUrl: null,
objectStorageBucket: null,
objectStoragePrefix: null,
objectStorageEndpoint: null,
objectStorageRegion: null,
objectStoragePort: null,
objectStorageAccessKey: null,
objectStorageSecretKey: null,
objectStorageUseSSL: false,
faHeadset, faShieldAlt, faGhost, faUserPlus, farEnvelope, faBolt, faThumbtack, faPencilAlt, faSave, faHashtag
};
},
@ -198,6 +317,9 @@ export default Vue.extend({
this.$root.getMeta(true).then(meta => {
this.maintainerName = meta.maintainerName;
this.maintainerEmail = meta.maintainerEmail;
this.ToSUrl = meta.ToSUrl;
this.repositoryUrl = meta.repositoryUrl;
this.feedbackUrl = meta.feedbackUrl;
this.disableRegistration = meta.disableRegistration;
this.disableLocalTimeline = meta.disableLocalTimeline;
this.disableGlobalTimeline = meta.disableGlobalTimeline;
@ -239,13 +361,28 @@ export default Vue.extend({
this.enableServiceWorker = meta.enableServiceWorker;
this.swPublicKey = meta.swPublickey;
this.swPrivateKey = meta.swPrivateKey;
this.pinnedUsers = meta.pinnedUsers.join('\n');
this.hiddenTags = meta.hiddenTags.join('\n');
this.useObjectStorage = meta.useObjectStorage;
this.objectStorageBaseUrl = meta.objectStorageBaseUrl;
this.objectStorageBucket = meta.objectStorageBucket;
this.objectStoragePrefix = meta.objectStoragePrefix;
this.objectStorageEndpoint = meta.objectStorageEndpoint;
this.objectStorageRegion = meta.objectStorageRegion;
this.objectStoragePort = meta.objectStoragePort;
this.objectStorageAccessKey = meta.objectStorageAccessKey;
this.objectStorageSecretKey = meta.objectStorageSecretKey;
this.objectStorageUseSSL = meta.objectStorageUseSSL;
});
},
methods: {
invite() {
this.$root.api('admin/invite').then(x => {
this.inviteCode = x.code;
this.$root.dialog({
type: 'info',
text: x.code
});
}).catch(e => {
this.$root.dialog({
type: 'error',
@ -258,6 +395,9 @@ export default Vue.extend({
this.$root.api('admin/update-meta', {
maintainerName: this.maintainerName,
maintainerEmail: this.maintainerEmail,
ToSUrl: this.ToSUrl,
repositoryUrl: this.repositoryUrl,
feedbackUrl: this.feedbackUrl,
disableRegistration: this.disableRegistration,
disableLocalTimeline: this.disableLocalTimeline,
disableGlobalTimeline: this.disableGlobalTimeline,
@ -297,7 +437,19 @@ export default Vue.extend({
smtpPass: this.smtpAuth ? this.smtpPass : '',
enableServiceWorker: this.enableServiceWorker,
swPublicKey: this.swPublicKey,
swPrivateKey: this.swPrivateKey
swPrivateKey: this.swPrivateKey,
pinnedUsers: this.pinnedUsers.split('\n'),
hiddenTags: this.hiddenTags.split('\n'),
useObjectStorage: this.useObjectStorage,
objectStorageBaseUrl: this.objectStorageBaseUrl ? this.objectStorageBaseUrl : null,
objectStorageBucket: this.objectStorageBucket ? this.objectStorageBucket : null,
objectStoragePrefix: this.objectStoragePrefix ? this.objectStoragePrefix : null,
objectStorageEndpoint: this.objectStorageEndpoint ? this.objectStorageEndpoint : null,
objectStorageRegion: this.objectStorageRegion ? this.objectStorageRegion : null,
objectStoragePort: this.objectStoragePort ? this.objectStoragePort : null,
objectStorageAccessKey: this.objectStorageAccessKey ? this.objectStorageAccessKey : null,
objectStorageSecretKey: this.objectStorageSecretKey ? this.objectStorageSecretKey : null,
objectStorageUseSSL: this.objectStorageUseSSL,
}).then(() => {
this.$root.dialog({
type: 'success',

View File

@ -11,7 +11,6 @@
<span class="username">@{{ user | acct }}</span>
<span class="is-admin" v-if="user.isAdmin">admin</span>
<span class="is-moderator" v-if="user.isModerator">moderator</span>
<span class="is-verified" v-if="user.isVerified" :title="$t('@.verified-user')"><fa icon="star"/></span>
<span class="is-silenced" v-if="user.isSilenced" :title="$t('@.silenced-user')"><fa :icon="faMicrophoneSlash"/></span>
<span class="is-suspended" v-if="user.isSuspended" :title="$t('@.suspended-user')"><fa :icon="faSnowflake"/></span>
</header>
@ -77,7 +76,6 @@ export default Vue.extend({
background var(--noteHeaderAdminBg)
color var(--noteHeaderAdminFg)
> .is-verified
> .is-silenced
> .is-suspended
margin 0 0 0 .5em

View File

@ -9,13 +9,10 @@
<ui-button @click="showUser"><fa :icon="faSearch"/> {{ $t('lookup') }}</ui-button>
<div class="user" v-if="user">
<x-user :user='user'/>
<x-user :user="user"/>
<div class="actions">
<ui-button v-if="user.host != null" @click="updateRemoteUser"><fa :icon="faSync"/> {{ $t('update-remote-user') }}</ui-button>
<ui-button @click="resetPassword"><fa :icon="faKey"/> {{ $t('reset-password') }}</ui-button>
<ui-horizon-group>
<ui-button @click="verifyUser" :disabled="verifying"><fa :icon="faCertificate"/> {{ $t('verify') }}</ui-button>
<ui-button @click="unverifyUser" :disabled="unverifying">{{ $t('unverify') }}</ui-button>
</ui-horizon-group>
<ui-horizon-group>
<ui-button @click="silenceUser"><fa :icon="faMicrophoneSlash"/> {{ $t('make-silence') }}</ui-button>
<ui-button @click="unsilenceUser">{{ $t('unmake-silence') }}</ui-button>
@ -24,7 +21,7 @@
<ui-button @click="suspendUser" :disabled="suspending"><fa :icon="faSnowflake"/> {{ $t('suspend') }}</ui-button>
<ui-button @click="unsuspendUser" :disabled="unsuspending">{{ $t('unsuspend') }}</ui-button>
</ui-horizon-group>
<ui-button v-if="user.host != null" @click="updateRemoteUser"><fa :icon="faSync"/> {{ $t('update-remote-user') }}</ui-button>
<ui-button @click="deleteAllFiles"><fa :icon="faTrashAlt"/> {{ $t('delete-all-files') }}</ui-button>
<ui-textarea v-if="user" :value="user | json5" readonly tall style="margin-top:16px;"></ui-textarea>
</div>
</div>
@ -47,7 +44,6 @@
<option value="all">{{ $t('users.state.all') }}</option>
<option value="admin">{{ $t('users.state.admin') }}</option>
<option value="moderator">{{ $t('users.state.moderator') }}</option>
<option value="verified">{{ $t('users.state.verified') }}</option>
<option value="silenced">{{ $t('users.state.silenced') }}</option>
<option value="suspended">{{ $t('users.state.suspended') }}</option>
</ui-select>
@ -71,8 +67,8 @@
import Vue from 'vue';
import i18n from '../../i18n';
import parseAcct from "../../../../misc/acct/parse";
import { faCertificate, faUsers, faTerminal, faSearch, faKey, faSync, faMicrophoneSlash } from '@fortawesome/free-solid-svg-icons';
import { faSnowflake } from '@fortawesome/free-regular-svg-icons';
import { faUsers, faTerminal, faSearch, faKey, faSync, faMicrophoneSlash } from '@fortawesome/free-solid-svg-icons';
import { faSnowflake, faTrashAlt } from '@fortawesome/free-regular-svg-icons';
import XUser from './users.user.vue';
export default Vue.extend({
@ -84,8 +80,6 @@ export default Vue.extend({
return {
user: null,
target: null,
verifying: false,
unverifying: false,
suspending: false,
unsuspending: false,
sort: '+createdAt',
@ -95,7 +89,7 @@ export default Vue.extend({
offset: 0,
users: [],
existMore: false,
faTerminal, faCertificate, faUsers, faSnowflake, faSearch, faKey, faSync, faMicrophoneSlash
faTerminal, faUsers, faSnowflake, faSearch, faKey, faSync, faMicrophoneSlash, faTrashAlt
};
},
@ -181,56 +175,6 @@ export default Vue.extend({
});
},
async verifyUser() {
if (!await this.getConfirmed(this.$t('verify-confirm'))) return;
this.verifying = true;
const process = async () => {
await this.$root.api('admin/verify-user', { userId: this.user.id });
this.$root.dialog({
type: 'success',
text: this.$t('verified')
});
};
await process().catch(e => {
this.$root.dialog({
type: 'error',
text: e.toString()
});
});
this.verifying = false;
this.refreshUser();
},
async unverifyUser() {
if (!await this.getConfirmed(this.$t('unverify-confirm'))) return;
this.unverifying = true;
const process = async () => {
await this.$root.api('admin/unverify-user', { userId: this.user.id });
this.$root.dialog({
type: 'success',
text: this.$t('unverified')
});
};
await process().catch(e => {
this.$root.dialog({
type: 'error',
text: e.toString()
});
});
this.unverifying = false;
this.refreshUser();
},
async silenceUser() {
if (!await this.getConfirmed(this.$t('silence-confirm'))) return;
@ -334,6 +278,25 @@ export default Vue.extend({
this.refreshUser();
},
async deleteAllFiles() {
if (!await this.getConfirmed(this.$t('delete-all-files-confirm'))) return;
const process = async () => {
await this.$root.api('admin/delete-all-files-of-a-user', { userId: this.user.id });
this.$root.dialog({
type: 'success',
splash: true
});
};
await process().catch(e => {
this.$root.dialog({
type: 'error',
text: e.toString()
});
});
},
async getConfirmed(text: string): Promise<Boolean> {
const confirm = await this.$root.dialog({
type: 'warning',

View File

@ -34,7 +34,7 @@ body
.peg
display block
position absolute
right 0px
right 0
width 100px
height 100%
box-shadow 0 0 10px var(--primary), 0 0 5px var(--primary)

View File

@ -98,7 +98,7 @@ export default Vue.extend({
margin 0 auto
text-align center
background #fff
box-shadow 0px 4px 16px rgba(#000, 0.2)
box-shadow 0 4px 16px rgba(#000, 0.2)
> .fetching
margin 0

View File

@ -52,7 +52,7 @@ function match(e: KeyboardEvent, patterns: action['patterns']): boolean {
pattern.ctrl == e.ctrlKey &&
pattern.shift == e.shiftKey &&
pattern.alt == e.altKey &&
e.metaKey == false
!e.metaKey
);
}

View File

@ -0,0 +1,42 @@
export function collectPageVars(content) {
const pageVars = [];
const collect = (xs: any[]) => {
for (const x of xs) {
if (x.type === 'textInput') {
pageVars.push({
name: x.name,
type: 'string',
value: x.default || ''
});
} else if (x.type === 'textareaInput') {
pageVars.push({
name: x.name,
type: 'string',
value: x.default || ''
});
} else if (x.type === 'numberInput') {
pageVars.push({
name: x.name,
type: 'number',
value: x.default || 0
});
} else if (x.type === 'switch') {
pageVars.push({
name: x.name,
type: 'boolean',
value: x.default || false
});
} else if (x.type === 'counter') {
pageVars.push({
name: x.name,
type: 'number',
value: 0
});
} else if (x.children) {
collect(x.children);
}
}
};
collect(content);
return pageVars;
}

View File

@ -0,0 +1,31 @@
import parseAcct from '../../../../misc/acct/parse';
import { host as localHost } from '../../config';
export async function genSearchQuery(v: any, q: string) {
let host: string;
let userId: string;
if (q.split(' ').some(x => x.startsWith('@'))) {
for (const at of q.split(' ').filter(x => x.startsWith('@')).map(x => x.substr(1))) {
if (at.includes('.')) {
if (at === localHost || at === '.') {
host = null;
} else {
host = at;
}
} else {
const user = await v.$root.api('users/show', parseAcct(at)).catch(x => null);
if (user) {
userId = user.id;
} else {
// todo: show error
}
}
}
}
return {
query: q.split(' ').filter(x => !x.startsWith('/') && !x.startsWith('@')).join(' '),
host: host,
userId: userId
};
}

View File

@ -3,7 +3,7 @@ import { faHistory } from '@fortawesome/free-solid-svg-icons';
export async function search(v: any, q: string) {
q = q.trim();
if (q.startsWith('@')) {
if (q.startsWith('@') && !q.includes(' ')) {
v.$router.push(`/${q}`);
return;
}

View File

@ -11,9 +11,9 @@ export default function(me, settings, note) {
return (
(!isMyNote && note.reply && includesMutedWords(note.reply.text)) ||
(!isMyNote && note.renote && includesMutedWords(note.renote.text)) ||
(settings.showMyRenotes === false && isMyNote && isPureRenote) ||
(settings.showRenotedMyNotes === false && isPureRenote && note.renote.userId == me.id) ||
(settings.showLocalRenotes === false && isPureRenote && note.renote.user.host == null) ||
(!settings.showMyRenotes && isMyNote && isPureRenote) ||
(!settings.showRenotedMyNotes && isPureRenote && note.renote.userId == me.id) ||
(!settings.showLocalRenotes && isPureRenote && note.renote.user.host == null) ||
(!isMyNote && includesMutedWords(note.text))
);
}

View File

@ -21,7 +21,7 @@ export default class Stream extends EventEmitter {
const user = os.store.state.i;
this.stream = new ReconnectingWebsocket(wsUrl + (user ? `?i=${user.token}` : ''));
this.stream = new ReconnectingWebsocket(wsUrl + (user ? `?i=${user.token}` : ''), '', { minReconnectionDelay: 1 }); // https://github.com/pladaria/reconnecting-websocket/issues/91
this.stream.addEventListener('open', this.onOpen);
this.stream.addEventListener('close', this.onClose);
this.stream.addEventListener('message', this.onMessage);

View File

@ -80,7 +80,7 @@ export default Vue.extend({
ms(): number {
return this.now.getMilliseconds() * this.smooth;
}
},
s(): number {
return this.now.getSeconds();
},

View File

@ -78,6 +78,7 @@ export default Vue.extend({
.mk-avatar
display inline-block
vertical-align bottom
flex-shrink 0
&:not(.cat)
overflow hidden

View File

@ -1,7 +1,7 @@
<template>
<div class="felqjxyj" :class="{ splash }">
<div class="bg" ref="bg" @click="onBgClick"></div>
<div class="main" ref="main">
<div class="main" ref="main" :class="{ round: $store.state.device.roundedCorners }">
<template v-if="type == 'signin'">
<mk-signin/>
</template>
@ -22,7 +22,14 @@
<ui-input v-if="input" v-model="inputValue" autofocus :type="input.type || 'text'" :placeholder="input.placeholder" @keydown="onInputKeydown"></ui-input>
<ui-input v-if="user" v-model="userInputValue" autofocus @keydown="onInputKeydown"><template #prefix>@</template></ui-input>
<ui-select v-if="select" v-model="selectedValue" autofocus>
<option v-for="item in select.items" :value="item.value">{{ item.text }}</option>
<template v-if="select.items">
<option v-for="item in select.items" :value="item.value">{{ item.text }}</option>
</template>
<template v-else>
<optgroup v-for="groupedItem in select.groupedItems" :label="groupedItem.label">
<option v-for="item in groupedItem.items" :value="item.value">{{ item.text }}</option>
</optgroup>
</template>
</ui-select>
<ui-horizon-group no-grow class="buttons fit-bottom" v-if="!splash && (showOkButton || showCancelButton)">
<ui-button @click="ok" v-if="showOkButton" primary :autofocus="!input && !select && !user">{{ (showCancelButton || input || select || user) ? $t('@.ok') : $t('@.got-it') }}</ui-button>
@ -222,15 +229,17 @@ export default Vue.extend({
width calc(100% - 32px)
text-align center
background var(--face)
border-radius 8px
color var(--faceText)
opacity 0
&.round
border-radius 8px
> .icon
font-size 32px
&.success
color #37ec92
color #85da5a
&.error
color #ec4137

View File

@ -1,5 +1,5 @@
<template>
<a class="a" :href="repositoryUrl" target="_blank" title="View source on GitHub">
<a class="a" :href="repositoryUrl" rel="noopener" target="_blank" title="View source on GitHub">
<svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="aria-hidden">
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
<path class="octo-arm" 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"></path>

View File

@ -200,6 +200,7 @@ export default Vue.extend({
// 通信を取りこぼしてもいいように定期的にポーリングさせる
if (this.game.isStarted && !this.game.isEnded) {
this.pollingClock = setInterval(() => {
if (this.game.isEnded) return;
const crc32 = CRC32.str(this.logs.map(x => x.pos.toString()).join(''));
this.connection.send('check', {
crc32: crc32

View File

@ -230,7 +230,7 @@ export default Vue.extend({
this.game.map = Object.values(maps).find(x => x.name == this.mapName).data;
}
this.$forceUpdate();
this.updateSettings();
this.updateSettings('map');
},
onPixelClick(pos, pixel) {

View File

@ -1,5 +1,5 @@
<template>
<a class="zxrjzpcj" :href="url" :class="service" target="_blank">
<a class="zxrjzpcj" :href="url" :class="service" rel="noopener" target="_blank">
<fa :icon="icon" size="lg" fixed-width /><span>{{ text }}</span>
</a>
</template>

View File

@ -36,7 +36,7 @@ export default Vue.extend({
return {
hide: true
};
}
},
computed: {
style(): any {
let url = `url(${

View File

@ -9,7 +9,7 @@
<div class="content" v-if="!message.isDeleted">
<mfm class="text" v-if="message.text" ref="text" :text="message.text" :i="$store.state.i"/>
<div class="file" v-if="message.file">
<a :href="message.file.url" target="_blank" :title="message.file.name">
<a :href="message.file.url" rel="noopener" target="_blank" :title="message.file.name">
<img v-if="message.file.type.split('/')[0] == 'image'" :src="message.file.url" :alt="message.file.name"
:style="{ backgroundColor: message.file.properties.avgColor || 'transparent' }"/>
<p v-else>{{ message.file.name }}</p>

View File

@ -13,8 +13,8 @@
@click="navigate(user)"
tabindex="-1"
>
<mk-avatar class="avatar" :user="user"/>
<span class="name"><mk-user-name :user="user"/></span>
<mk-avatar class="avatar" :user="user" :key="user.id"/>
<span class="name"><mk-user-name :user="user" :key="user.id"/></span>
<span class="username">@{{ user | acct }}</span>
</li>
</ol>
@ -202,7 +202,7 @@ export default Vue.extend({
left 0
z-index 1
width 100%
box-shadow 0 0px 2px rgba(#000, 0.2)
box-shadow 0 0 2px rgba(#000, 0.2)
> .form
background rgba(0, 0, 0, 0.02)

View File

@ -174,6 +174,7 @@ export default Vue.component('misskey-flavored-markdown', {
key: Math.random(),
props: {
url: token.node.props.url,
rel: 'nofollow noopener',
target: '_blank'
},
attrs: {
@ -187,6 +188,7 @@ export default Vue.component('misskey-flavored-markdown', {
attrs: {
class: 'link',
href: token.node.props.url,
rel: 'nofollow noopener',
target: '_blank',
title: token.node.props.url,
style: 'color:var(--mfmLink);'

View File

@ -1,12 +1,16 @@
<template>
<span class="mk-nav">
<a :href="aboutUrl">{{ $t('about') }}</a>
<template v-if="ToSUrl !== null">
<i></i>
<a :href="ToSUrl" target="_blank">{{ $t('tos') }}</a>
</template>
<i></i>
<a :href="repositoryUrl">{{ $t('repository') }}</a>
<a :href="repositoryUrl" rel="noopener" target="_blank">{{ $t('repository') }}</a>
<i></i>
<a :href="feedbackUrl" target="_blank">{{ $t('feedback') }}</a>
<a :href="feedbackUrl" rel="noopener" target="_blank">{{ $t('feedback') }}</a>
<i></i>
<a href="/dev">{{ $t('develop') }}</a>
<a href="/dev" target="_blank">{{ $t('develop') }}</a>
</span>
</template>
@ -21,8 +25,17 @@ export default Vue.extend({
return {
aboutUrl: `/docs/${lang}/about`,
repositoryUrl: 'https://github.com/syuilo/misskey',
feedbackUrl: 'https://github.com/syuilo/misskey/issues/new'
feedbackUrl: 'https://github.com/syuilo/misskey/issues/new',
ToSUrl: null
}
},
mounted() {
this.$root.getMeta(true).then(meta => {
this.repositoryUrl = meta.repositoryUrl;
this.feedbackUrl = meta.feedbackUrl;
this.ToSUrl = meta.ToSUrl;
})
}
});
</script>

View File

@ -8,7 +8,6 @@
<span class="is-bot" v-if="note.user.isBot">bot</span>
<span class="is-cat" v-if="note.user.isCat">cat</span>
<span class="username"><mk-acct :user="note.user"/></span>
<span class="is-verified" v-if="note.user.isVerified" :title="$t('@.verified-user')"><fa icon="star"/></span>
<div class="info">
<span class="app" v-if="note.app && !mini && $store.state.settings.showVia">via <b>{{ note.app.name }}</b></span>
<span class="mobile" v-if="note.viaMobile"><fa icon="mobile-alt"/></span>
@ -95,10 +94,6 @@ export default Vue.extend({
color var(--noteHeaderAcct)
flex-shrink 2147483647
> .is-verified
margin 0 .5em 0 0
color #4dabf7
> .info
margin-left auto
font-size 0.9em

View File

@ -0,0 +1,54 @@
<template>
<x-container @remove="() => $emit('remove')" :draggable="true">
<template #header><fa :icon="faBolt"/> {{ $t('blocks.button') }}</template>
<section class="xfhsjczc">
<ui-input v-model="value.text"><span>{{ $t('blocks._button.text') }}</span></ui-input>
<ui-select v-model="value.action">
<template #label>{{ $t('blocks._button.action') }}</template>
<option value="dialog">{{ $t('blocks._button._action.dialog') }}</option>
<option value="resetRandom">{{ $t('blocks._button._action.resetRandom') }}</option>
</ui-select>
<ui-input v-if="value.action === 'dialog'" v-model="value.content"><span>{{ $t('blocks._button._action._dialog.content') }}</span></ui-input>
</section>
</x-container>
</template>
<script lang="ts">
import Vue from 'vue';
import { faBolt } from '@fortawesome/free-solid-svg-icons';
import i18n from '../../../../../i18n';
import XContainer from '../page-editor.container.vue';
export default Vue.extend({
i18n: i18n('pages'),
components: {
XContainer
},
props: {
value: {
required: true
},
},
data() {
return {
faBolt
};
},
created() {
if (this.value.text == null) Vue.set(this.value, 'text', '');
if (this.value.action == null) Vue.set(this.value, 'action', 'dialog');
if (this.value.content == null) Vue.set(this.value, 'content', null);
},
});
</script>
<style lang="stylus" scoped>
.xfhsjczc
padding 0 16px 0 16px
</style>

View File

@ -0,0 +1,42 @@
<template>
<x-container @remove="() => $emit('remove')" :draggable="true">
<template #header><fa :icon="faBolt"/> {{ $t('blocks.counter') }}</template>
<section style="padding: 0 16px 0 16px;">
<ui-input v-model="value.name"><template #prefix><fa :icon="faMagic"/></template><span>{{ $t('blocks._counter.name') }}</span></ui-input>
<ui-input v-model="value.text"><span>{{ $t('blocks._counter.text') }}</span></ui-input>
<ui-input v-model="value.inc" type="number"><span>{{ $t('blocks._counter.increment') }}</span></ui-input>
</section>
</x-container>
</template>
<script lang="ts">
import Vue from 'vue';
import { faBolt, faMagic } from '@fortawesome/free-solid-svg-icons';
import i18n from '../../../../../i18n';
import XContainer from '../page-editor.container.vue';
export default Vue.extend({
i18n: i18n('pages'),
components: {
XContainer
},
props: {
value: {
required: true
},
},
data() {
return {
faBolt, faMagic
};
},
created() {
if (this.value.name == null) Vue.set(this.value, 'name', '');
},
});
</script>

View File

@ -0,0 +1,90 @@
<template>
<x-container @remove="() => $emit('remove')" :draggable="true">
<template #header><fa :icon="faQuestion"/> {{ $t('blocks.if') }}</template>
<template #func>
<button @click="add()">
<fa :icon="faPlus"/>
</button>
</template>
<section class="romcojzs">
<ui-select v-model="value.var">
<template #label>{{ $t('blocks._if.variable') }}</template>
<option v-for="v in aiScript.getVarsByType('boolean')" :value="v.name">{{ v.name }}</option>
<optgroup :label="$t('script.pageVariables')">
<option v-for="v in aiScript.getPageVarsByType('boolean')" :value="v">{{ v }}</option>
</optgroup>
<optgroup :label="$t('script.enviromentVariables')">
<option v-for="v in aiScript.getEnvVarsByType('boolean')" :value="v">{{ v }}</option>
</optgroup>
</ui-select>
<x-blocks class="children" v-model="value.children" :ai-script="aiScript"/>
</section>
</x-container>
</template>
<script lang="ts">
import Vue from 'vue';
import * as uuid from 'uuid';
import { faPlus, faQuestion } from '@fortawesome/free-solid-svg-icons';
import i18n from '../../../../../i18n';
import XContainer from '../page-editor.container.vue';
export default Vue.extend({
i18n: i18n('pages'),
components: {
XContainer
},
inject: ['getPageBlockList'],
props: {
value: {
required: true
},
aiScript: {
required: true,
},
},
data() {
return {
faPlus, faQuestion
};
},
beforeCreate() {
this.$options.components.XBlocks = require('../page-editor.blocks.vue').default
},
created() {
if (this.value.children == null) Vue.set(this.value, 'children', []);
if (this.value.var === undefined) Vue.set(this.value, 'var', null);
},
methods: {
async add() {
const { canceled, result: type } = await this.$root.dialog({
type: null,
title: this.$t('choose-block'),
select: {
groupedItems: this.getPageBlockList()
},
showCancelButton: true
});
if (canceled) return;
const id = uuid.v4();
this.value.children.push({ id, type });
},
}
});
</script>
<style lang="stylus" scoped>
.romcojzs
padding 0 16px 16px 16px
</style>

View File

@ -0,0 +1,78 @@
<template>
<x-container @remove="() => $emit('remove')" :draggable="true">
<template #header><fa :icon="faImage"/> {{ $t('blocks.image') }}</template>
<template #func>
<button @click="choose()">
<fa :icon="faFolderOpen"/>
</button>
</template>
<section class="oyyftmcf">
<x-file-thumbnail class="preview" v-if="file" :file="file" :detail="true" fit="contain" @click="choose()"/>
</section>
</x-container>
</template>
<script lang="ts">
import Vue from 'vue';
import { faPencilAlt } from '@fortawesome/free-solid-svg-icons';
import { faImage, faFolderOpen } from '@fortawesome/free-regular-svg-icons';
import i18n from '../../../../../i18n';
import XContainer from '../page-editor.container.vue';
import XFileThumbnail from '../../drive-file-thumbnail.vue';
export default Vue.extend({
i18n: i18n('pages'),
components: {
XContainer, XFileThumbnail
},
props: {
value: {
required: true
},
},
data() {
return {
file: null,
faPencilAlt, faImage, faFolderOpen
};
},
created() {
if (this.value.fileId === undefined) Vue.set(this.value, 'fileId', null);
},
mounted() {
if (this.value.fileId == null) {
this.choose();
} else {
this.$root.api('drive/files/show', {
fileId: this.value.fileId
}).then(file => {
this.file = file;
});
}
},
methods: {
async choose() {
this.$chooseDriveFile({
multiple: false
}).then(file => {
this.file = file;
this.value.fileId = file.id;
});
},
}
});
</script>
<style lang="stylus" scoped>
.oyyftmcf
> .preview
height 150px
</style>

View File

@ -0,0 +1,42 @@
<template>
<x-container @remove="() => $emit('remove')" :draggable="true">
<template #header><fa :icon="faBolt"/> {{ $t('blocks.numberInput') }}</template>
<section style="padding: 0 16px 0 16px;">
<ui-input v-model="value.name"><template #prefix><fa :icon="faMagic"/></template><span>{{ $t('blocks._numberInput.name') }}</span></ui-input>
<ui-input v-model="value.text"><span>{{ $t('blocks._numberInput.text') }}</span></ui-input>
<ui-input v-model="value.default" type="number"><span>{{ $t('blocks._numberInput.default') }}</span></ui-input>
</section>
</x-container>
</template>
<script lang="ts">
import Vue from 'vue';
import { faBolt, faMagic } from '@fortawesome/free-solid-svg-icons';
import i18n from '../../../../../i18n';
import XContainer from '../page-editor.container.vue';
export default Vue.extend({
i18n: i18n('pages'),
components: {
XContainer
},
props: {
value: {
required: true
},
},
data() {
return {
faBolt, faMagic
};
},
created() {
if (this.value.name == null) Vue.set(this.value, 'name', '');
},
});
</script>

View File

@ -0,0 +1,40 @@
<template>
<x-container @remove="() => $emit('remove')" :draggable="true">
<template #header><fa :icon="faPaperPlane"/> {{ $t('blocks.post') }}</template>
<section style="padding: 0 16px 16px 16px;">
<ui-textarea v-model="value.text">{{ $t('blocks._post.text') }}</ui-textarea>
</section>
</x-container>
</template>
<script lang="ts">
import Vue from 'vue';
import { faPaperPlane } from '@fortawesome/free-regular-svg-icons';
import i18n from '../../../../../i18n';
import XContainer from '../page-editor.container.vue';
export default Vue.extend({
i18n: i18n('pages'),
components: {
XContainer
},
props: {
value: {
required: true
},
},
data() {
return {
faPaperPlane
};
},
created() {
if (this.value.text == null) Vue.set(this.value, 'text', '');
},
});
</script>

View File

@ -0,0 +1,103 @@
<template>
<x-container @remove="() => $emit('remove')" :draggable="true">
<template #header><fa :icon="faStickyNote"/> {{ value.title }}</template>
<template #func>
<button @click="rename()">
<fa :icon="faPencilAlt"/>
</button>
<button @click="add()">
<fa :icon="faPlus"/>
</button>
</template>
<section class="ilrvjyvi">
<x-blocks class="children" v-model="value.children" :ai-script="aiScript"/>
</section>
</x-container>
</template>
<script lang="ts">
import Vue from 'vue';
import * as uuid from 'uuid';
import { faPlus, faPencilAlt } from '@fortawesome/free-solid-svg-icons';
import { faStickyNote } from '@fortawesome/free-regular-svg-icons';
import i18n from '../../../../../i18n';
import XContainer from '../page-editor.container.vue';
export default Vue.extend({
i18n: i18n('pages'),
components: {
XContainer
},
inject: ['getPageBlockList'],
props: {
value: {
required: true
},
aiScript: {
required: true,
},
},
data() {
return {
faStickyNote, faPlus, faPencilAlt
};
},
beforeCreate() {
this.$options.components.XBlocks = require('../page-editor.blocks.vue').default
},
created() {
if (this.value.title == null) Vue.set(this.value, 'title', null);
if (this.value.children == null) Vue.set(this.value, 'children', []);
},
mounted() {
if (this.value.title == null) {
this.rename();
}
},
methods: {
async rename() {
const { canceled, result: title } = await this.$root.dialog({
title: 'Enter title',
input: {
type: 'text',
default: this.value.title
},
showCancelButton: true
});
if (canceled) return;
this.value.title = title;
},
async add() {
const { canceled, result: type } = await this.$root.dialog({
type: null,
title: this.$t('choose-block'),
select: {
groupedItems: this.getPageBlockList()
},
showCancelButton: true
});
if (canceled) return;
const id = uuid.v4();
this.value.children.push({ id, type });
},
}
});
</script>
<style lang="stylus" scoped>
.ilrvjyvi
> .children
padding 16px
</style>

View File

@ -0,0 +1,48 @@
<template>
<x-container @remove="() => $emit('remove')" :draggable="true">
<template #header><fa :icon="faBolt"/> {{ $t('blocks.switch') }}</template>
<section class="kjuadyyj">
<ui-input v-model="value.name"><template #prefix><fa :icon="faMagic"/></template><span>{{ $t('blocks._switch.name') }}</span></ui-input>
<ui-input v-model="value.text"><span>{{ $t('blocks._switch.text') }}</span></ui-input>
<ui-switch v-model="value.default"><span>{{ $t('blocks._switch.default') }}</span></ui-switch>
</section>
</x-container>
</template>
<script lang="ts">
import Vue from 'vue';
import { faBolt, faMagic } from '@fortawesome/free-solid-svg-icons';
import i18n from '../../../../../i18n';
import XContainer from '../page-editor.container.vue';
export default Vue.extend({
i18n: i18n('pages'),
components: {
XContainer
},
props: {
value: {
required: true
},
},
data() {
return {
faBolt, faMagic
};
},
created() {
if (this.value.name == null) Vue.set(this.value, 'name', '');
},
});
</script>
<style lang="stylus" scoped>
.kjuadyyj
padding 0 16px 16px 16px
</style>

View File

@ -0,0 +1,42 @@
<template>
<x-container @remove="() => $emit('remove')" :draggable="true">
<template #header><fa :icon="faBolt"/> {{ $t('blocks.textInput') }}</template>
<section style="padding: 0 16px 0 16px;">
<ui-input v-model="value.name"><template #prefix><fa :icon="faMagic"/></template><span>{{ $t('blocks._textInput.name') }}</span></ui-input>
<ui-input v-model="value.text"><span>{{ $t('blocks._textInput.text') }}</span></ui-input>
<ui-input v-model="value.default" type="text"><span>{{ $t('blocks._textInput.default') }}</span></ui-input>
</section>
</x-container>
</template>
<script lang="ts">
import Vue from 'vue';
import { faBolt, faMagic } from '@fortawesome/free-solid-svg-icons';
import i18n from '../../../../../i18n';
import XContainer from '../page-editor.container.vue';
export default Vue.extend({
i18n: i18n('pages'),
components: {
XContainer
},
props: {
value: {
required: true
},
},
data() {
return {
faBolt, faMagic
};
},
created() {
if (this.value.name == null) Vue.set(this.value, 'name', '');
},
});
</script>

View File

@ -0,0 +1,58 @@
<template>
<x-container @remove="() => $emit('remove')" :draggable="true">
<template #header><fa :icon="faAlignLeft"/> {{ $t('blocks.text') }}</template>
<section class="ihymsbbe">
<textarea v-model="value.text"></textarea>
</section>
</x-container>
</template>
<script lang="ts">
import Vue from 'vue';
import { faAlignLeft } from '@fortawesome/free-solid-svg-icons';
import i18n from '../../../../../i18n';
import XContainer from '../page-editor.container.vue';
export default Vue.extend({
i18n: i18n('pages'),
components: {
XContainer
},
props: {
value: {
required: true
},
},
data() {
return {
faAlignLeft,
};
},
created() {
if (this.value.text == null) Vue.set(this.value, 'text', '');
},
});
</script>
<style lang="stylus" scoped>
.ihymsbbe
> textarea
display block
-webkit-appearance none
-moz-appearance none
appearance none
width 100%
min-width 100%
min-height 150px
border none
box-shadow none
padding 16px
background transparent
color var(--text)
font-size 14px
</style>

View File

@ -0,0 +1,42 @@
<template>
<x-container @remove="() => $emit('remove')" :draggable="true">
<template #header><fa :icon="faBolt"/> {{ $t('blocks.textareaInput') }}</template>
<section style="padding: 0 16px 16px 16px;">
<ui-input v-model="value.name"><template #prefix><fa :icon="faMagic"/></template><span>{{ $t('blocks._textareaInput.name') }}</span></ui-input>
<ui-input v-model="value.text"><span>{{ $t('blocks._textareaInput.text') }}</span></ui-input>
<ui-textarea v-model="value.default"><span>{{ $t('blocks._textareaInput.default') }}</span></ui-textarea>
</section>
</x-container>
</template>
<script lang="ts">
import Vue from 'vue';
import { faBolt, faMagic } from '@fortawesome/free-solid-svg-icons';
import i18n from '../../../../../i18n';
import XContainer from '../page-editor.container.vue';
export default Vue.extend({
i18n: i18n('pages'),
components: {
XContainer
},
props: {
value: {
required: true
},
},
data() {
return {
faBolt, faMagic
};
},
created() {
if (this.value.name == null) Vue.set(this.value, 'name', '');
},
});
</script>

View File

@ -0,0 +1,58 @@
<template>
<x-container @remove="() => $emit('remove')" :draggable="true">
<template #header><fa :icon="faAlignLeft"/> {{ $t('blocks.textarea') }}</template>
<section class="ihymsbbe">
<textarea v-model="value.text"></textarea>
</section>
</x-container>
</template>
<script lang="ts">
import Vue from 'vue';
import { faAlignLeft } from '@fortawesome/free-solid-svg-icons';
import i18n from '../../../../../i18n';
import XContainer from '../page-editor.container.vue';
export default Vue.extend({
i18n: i18n('pages'),
components: {
XContainer
},
props: {
value: {
required: true
},
},
data() {
return {
faAlignLeft,
};
},
created() {
if (this.value.text == null) Vue.set(this.value, 'text', '');
},
});
</script>
<style lang="stylus" scoped>
.ihymsbbe
> textarea
display block
-webkit-appearance none
-moz-appearance none
appearance none
width 100%
min-width 100%
min-height 150px
border none
box-shadow none
padding 16px
background transparent
color var(--text)
font-size 14px
</style>

View File

@ -0,0 +1,65 @@
<template>
<x-draggable tag="div" :list="blocks" handle=".drag-handle" :group="{ name: 'blocks' }" animation="150" swap-threshold="0.5">
<component v-for="block in blocks" :is="'x-' + block.type" :value="block" @input="updateItem" @remove="() => removeItem(block)" :key="block.id" :ai-script="aiScript"/>
</x-draggable>
</template>
<script lang="ts">
import Vue from 'vue';
import * as XDraggable from 'vuedraggable';
import XSection from './els/page-editor.el.section.vue';
import XText from './els/page-editor.el.text.vue';
import XTextarea from './els/page-editor.el.textarea.vue';
import XImage from './els/page-editor.el.image.vue';
import XButton from './els/page-editor.el.button.vue';
import XTextInput from './els/page-editor.el.text-input.vue';
import XTextareaInput from './els/page-editor.el.textarea-input.vue';
import XNumberInput from './els/page-editor.el.number-input.vue';
import XSwitch from './els/page-editor.el.switch.vue';
import XIf from './els/page-editor.el.if.vue';
import XPost from './els/page-editor.el.post.vue';
import XCounter from './els/page-editor.el.counter.vue';
export default Vue.extend({
components: {
XDraggable, XSection, XText, XImage, XButton, XTextarea, XTextInput, XTextareaInput, XNumberInput, XSwitch, XIf, XPost, XCounter
},
props: {
value: {
type: Array,
required: true
},
aiScript: {
required: true,
},
},
computed: {
blocks() {
return this.value;
}
},
methods: {
updateItem(v) {
const i = this.blocks.findIndex(x => x.id === v.id);
const newValue = [
...this.blocks.slice(0, i),
v,
...this.blocks.slice(i + 1)
];
this.$emit('input', newValue);
},
removeItem(el) {
const i = this.blocks.findIndex(x => x.id === el.id);
const newValue = [
...this.blocks.slice(0, i),
...this.blocks.slice(i + 1)
];
this.$emit('input', newValue);
},
}
});
</script>

View File

@ -0,0 +1,146 @@
<template>
<div class="cpjygsrt" :class="{ error: error != null, warn: warn != null }">
<header>
<div class="title"><slot name="header"></slot></div>
<div class="buttons">
<slot name="func"></slot>
<button v-if="removable" @click="remove()">
<fa :icon="faTrashAlt"/>
</button>
<button v-if="draggable" class="drag-handle">
<fa :icon="faBars"/>
</button>
<button @click="toggleContent(!showBody)">
<template v-if="showBody"><fa icon="angle-up"/></template>
<template v-else><fa icon="angle-down"/></template>
</button>
</div>
</header>
<p v-show="showBody" class="error" v-if="error != null">{{ $t('script.typeError', { slot: error.arg + 1, expect: $t(`script.types.${error.expect}`), actual: $t(`script.types.${error.actual}`) }) }}</p>
<p v-show="showBody" class="warn" v-if="warn != null">{{ $t('script.thereIsEmptySlot', { slot: warn.slot + 1 }) }}</p>
<div v-show="showBody">
<slot></slot>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import { faBars } from '@fortawesome/free-solid-svg-icons';
import { faTrashAlt } from '@fortawesome/free-regular-svg-icons';
import i18n from '../../../../i18n';
export default Vue.extend({
i18n: i18n('pages'),
props: {
expanded: {
type: Boolean,
default: true
},
removable: {
type: Boolean,
default: true
},
draggable: {
type: Boolean,
default: false
},
error: {
required: false,
default: null
},
warn: {
required: false,
default: null
}
},
data() {
return {
showBody: this.expanded,
faTrashAlt, faBars
};
},
methods: {
toggleContent(show: boolean) {
this.showBody = show;
this.$emit('toggle', show);
},
remove() {
this.$emit('remove');
}
}
});
</script>
<style lang="stylus" scoped>
.cpjygsrt
overflow hidden
background var(--face)
border solid 2px var(--pageBlockBorder)
border-radius 6px
&:hover
border solid 2px var(--pageBlockBorderHover)
&.warn
border solid 2px #dec44c
&.error
border solid 2px #f00
& + .cpjygsrt
margin-top 16px
> header
> .title
z-index 1
margin 0
padding 0 16px
line-height 42px
font-size 0.9em
font-weight bold
color var(--faceHeaderText)
box-shadow 0 1px rgba(#000, 0.07)
> [data-icon]
margin-right 6px
&:empty
display none
> .buttons
position absolute
z-index 2
top 0
right 0
> button
padding 0
width 42px
font-size 0.9em
line-height 42px
color var(--faceTextButton)
&:hover
color var(--faceTextButtonHover)
&:active
color var(--faceTextButtonActive)
.drag-handle
cursor move
> .warn
color #b19e49
margin 0
padding 16px 16px 0 16px
font-size 14px
> .error
color #f00
margin 0
padding 16px 16px 0 16px
font-size 14px
</style>

View File

@ -0,0 +1,271 @@
<template>
<x-container :removable="removable" @remove="() => $emit('remove')" :error="error" :warn="warn" :draggable="draggable">
<template #header><fa v-if="icon" :icon="icon"/> <template v-if="title">{{ title }} <span class="turmquns" v-if="typeText">({{ typeText }})</span></template><template v-else-if="typeText">{{ typeText }}</template></template>
<template #func>
<button @click="changeType()">
<fa :icon="faPencilAlt"/>
</button>
</template>
<section v-if="value.type === null" class="pbglfege" @click="changeType()">
{{ $t('script.emptySlot') }}
</section>
<section v-else-if="value.type === 'text'" class="tbwccoaw">
<input v-model="value.value"/>
</section>
<section v-else-if="value.type === 'multiLineText'" class="tbwccoaw">
<textarea v-model="value.value"></textarea>
</section>
<section v-else-if="value.type === 'textList'" class="tbwccoaw">
<textarea v-model="value.value" :placeholder="$t('script.blocks._textList.info')"></textarea>
</section>
<section v-else-if="value.type === 'number'" class="tbwccoaw">
<input v-model="value.value" type="number"/>
</section>
<section v-else-if="value.type === 'ref'" class="hpdwcrvs">
<select v-model="value.value">
<option v-for="v in aiScript.getVarsByType(getExpectedType ? getExpectedType() : null).filter(x => x.name !== name)" :value="v.name">{{ v.name }}</option>
<optgroup :label="$t('script.argVariables')">
<option v-for="v in fnSlots" :value="v.name">{{ v.name }}</option>
</optgroup>
<optgroup :label="$t('script.pageVariables')">
<option v-for="v in aiScript.getPageVarsByType(getExpectedType ? getExpectedType() : null)" :value="v">{{ v }}</option>
</optgroup>
<optgroup :label="$t('script.enviromentVariables')">
<option v-for="v in aiScript.getEnvVarsByType(getExpectedType ? getExpectedType() : null)" :value="v">{{ v }}</option>
</optgroup>
</select>
</section>
<section v-else-if="value.type === 'fn'" class="" style="padding:0 16px 16px 16px;">
<ui-textarea v-model="slots">
<span>{{ $t('script.blocks._fn.slots') }}</span>
<template #desc>{{ $t('script.blocks._fn.slots-info') }}</template>
</ui-textarea>
<x-v v-if="value.value.expression" v-model="value.value.expression" :title="$t(`script.blocks._fn.arg1`)" :get-expected-type="() => null" :ai-script="aiScript" :fn-slots="value.value.slots" :name="name"/>
</section>
<section v-else-if="value.type.startsWith('fn:')" class="" style="padding:16px;">
<x-v v-for="(x, i) in value.args" v-model="value.args[i]" :title="aiScript.getVarByName(value.type.split(':')[1]).value.slots[i].name" :get-expected-type="() => null" :ai-script="aiScript" :name="name" :key="i"/>
</section>
<section v-else class="" style="padding:16px;">
<x-v v-for="(x, i) in value.args" v-model="value.args[i]" :title="$t(`script.blocks._${value.type}.arg${i + 1}`)" :get-expected-type="() => _getExpectedType(i)" :ai-script="aiScript" :name="name" :fn-slots="fnSlots" :key="i"/>
</section>
</x-container>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../../i18n';
import XContainer from './page-editor.container.vue';
import { faPencilAlt, faPlug } from '@fortawesome/free-solid-svg-icons';
import { isLiteralBlock, funcDefs, blockDefs } from '../../../../../../misc/aiscript/index';
import * as uuid from 'uuid';
export default Vue.extend({
i18n: i18n('pages'),
components: {
XContainer
},
inject: ['getScriptBlockList'],
props: {
getExpectedType: {
required: false,
default: null
},
value: {
required: true
},
title: {
required: false
},
removable: {
required: false,
default: false
},
aiScript: {
required: true,
},
name: {
required: true,
},
fnSlots: {
required: false,
},
draggable: {
required: false,
default: false
}
},
data() {
return {
error: null,
warn: null,
slots: '',
faPencilAlt
};
},
computed: {
icon(): any {
if (this.value.type === null) return null;
if (this.value.type.startsWith('fn:')) return faPlug;
return blockDefs.find(x => x.type === this.value.type).icon;
},
typeText(): any {
if (this.value.type === null) return null;
if (this.value.type.startsWith('fn:')) return this.value.type.split(':')[1];
return this.$t(`script.blocks.${this.value.type}`);
},
},
watch: {
slots() {
this.value.value.slots = this.slots.split('\n').map(x => ({
name: x,
type: null
}));
}
},
beforeCreate() {
this.$options.components.XV = require('./page-editor.script-block.vue').default;
},
created() {
if (this.value.value == null) Vue.set(this.value, 'value', null);
if (this.value.value && this.value.value.slots) this.slots = this.value.value.slots.map(x => x.name).join('\n');
this.$watch('value.type', (t) => {
this.warn = null;
if (this.value.type === 'fn') {
const id = uuid.v4();
this.value.value = {};
Vue.set(this.value.value, 'slots', []);
Vue.set(this.value.value, 'expression', { id, type: null });
return;
}
if (this.value.type && this.value.type.startsWith('fn:')) {
const fnName = this.value.type.split(':')[1];
const fn = this.aiScript.getVarByName(fnName);
const empties = [];
for (let i = 0; i < fn.value.slots.length; i++) {
const id = uuid.v4();
empties.push({ id, type: null });
}
Vue.set(this.value, 'args', empties);
return;
}
if (isLiteralBlock(this.value)) return;
const empties = [];
for (let i = 0; i < funcDefs[this.value.type].in.length; i++) {
const id = uuid.v4();
empties.push({ id, type: null });
}
Vue.set(this.value, 'args', empties);
for (let i = 0; i < funcDefs[this.value.type].in.length; i++) {
const inType = funcDefs[this.value.type].in[i];
if (typeof inType !== 'number') {
if (inType === 'number') this.value.args[i].type = 'number';
if (inType === 'string') this.value.args[i].type = 'text';
}
}
});
this.$watch('value.args', (args) => {
if (args == null) {
this.warn = null;
return;
}
const emptySlotIndex = args.findIndex(x => x.type === null);
if (emptySlotIndex !== -1 && emptySlotIndex < args.length) {
this.warn = {
slot: emptySlotIndex
};
} else {
this.warn = null;
}
}, {
deep: true
});
this.$watch('aiScript.variables', () => {
if (this.type != null && this.value) {
this.error = this.aiScript.typeCheck(this.value);
}
}, {
deep: true
});
},
methods: {
async changeType() {
const { canceled, result: type } = await this.$root.dialog({
type: null,
title: this.$t('select-type'),
select: {
groupedItems: this.getScriptBlockList(this.getExpectedType ? this.getExpectedType() : null)
},
showCancelButton: true
});
if (canceled) return;
this.value.type = type;
},
_getExpectedType(slot: number) {
return this.aiScript.getExpectedType(this.value, slot);
}
}
});
</script>
<style lang="stylus" scoped>
.turmquns
opacity 0.7
.pbglfege
opacity 0.5
padding 16px
text-align center
cursor pointer
color var(--text)
.tbwccoaw
> input
> textarea
display block
-webkit-appearance none
-moz-appearance none
appearance none
width 100%
max-width 100%
min-width 100%
border none
box-shadow none
padding 16px
font-size 16px
background transparent
color var(--text)
> textarea
min-height 100px
.hpdwcrvs
padding 16px
> select
display block
padding 4px
font-size 16px
width 100%
</style>

View File

@ -0,0 +1,473 @@
<template>
<div>
<div class="gwbmwxkm" :class="{ shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners }">
<header>
<div class="title"><fa :icon="faStickyNote"/> {{ readonly ? $t('read-page') : pageId ? $t('edit-page') : $t('new-page') }}</div>
<div class="buttons">
<button @click="del()" v-if="!readonly"><fa :icon="faTrashAlt"/></button>
<button @click="() => showOptions = !showOptions"><fa :icon="faCog"/></button>
<button @click="save()" v-if="!readonly"><fa :icon="faSave"/></button>
</div>
</header>
<section>
<a class="view" v-if="pageId" :href="`/@${ author.username }/pages/${ currentName }`" target="_blank"><fa :icon="faExternalLinkSquareAlt"/> {{ $t('view-page') }}</a>
<ui-input v-model="title">
<span>{{ $t('title') }}</span>
</ui-input>
<template v-if="showOptions">
<ui-input v-model="summary">
<span>{{ $t('summary') }}</span>
</ui-input>
<ui-input v-model="name">
<template #prefix>{{ url }}/@{{ author.username }}/pages/</template>
<span>{{ $t('url') }}</span>
</ui-input>
<ui-switch v-model="alignCenter">{{ $t('align-center') }}</ui-switch>
<ui-select v-model="font">
<template #label>{{ $t('font') }}</template>
<option value="serif">{{ $t('fontSerif') }}</option>
<option value="sans-serif">{{ $t('fontSansSerif') }}</option>
</ui-select>
<div class="eyeCatch">
<ui-button v-if="eyeCatchingImageId == null && !readonly" @click="setEyeCatchingImage()"><fa :icon="faPlus"/> {{ $t('set-eye-catching-image') }}</ui-button>
<div v-else-if="eyeCatchingImage">
<img :src="eyeCatchingImage.url" :alt="eyeCatchingImage.name"/>
<ui-button @click="removeEyeCatchingImage()" v-if="!readonly"><fa :icon="faTrashAlt"/> {{ $t('remove-eye-catching-image') }}</ui-button>
</div>
</div>
</template>
<x-blocks class="content" v-model="content" :ai-script="aiScript"/>
<ui-button @click="add()" v-if="!readonly"><fa :icon="faPlus"/></ui-button>
</section>
</div>
<ui-container :body-togglable="true">
<template #header><fa :icon="faMagic"/> {{ $t('variables') }}</template>
<div class="qmuvgica">
<x-draggable tag="div" class="variables" v-show="variables.length > 0" :list="variables" handle=".drag-handle" :group="{ name: 'variables' }" animation="150" swap-threshold="0.5">
<x-variable v-for="variable in variables"
:value="variable"
:removable="true"
@input="v => updateVariable(v)"
@remove="() => removeVariable(variable)"
:key="variable.name"
:ai-script="aiScript"
:name="variable.name"
:title="variable.name"
:draggable="true"
/>
</x-draggable>
<ui-button @click="addVariable()" class="add" v-if="!readonly"><fa :icon="faPlus"/></ui-button>
<ui-info><span v-html="$t('variables-info')"></span><a @click="() => moreDetails = true" style="display:block;">{{ $t('more-details') }}</a></ui-info>
<template v-if="moreDetails">
<ui-info><span v-html="$t('variables-info2')"></span></ui-info>
<ui-info><span v-html="$t('variables-info3')"></span></ui-info>
<ui-info><span v-html="$t('variables-info4')"></span></ui-info>
</template>
</div>
</ui-container>
<ui-container :body-togglable="true" :expanded="false">
<template #header><fa :icon="faCode"/> {{ $t('inspector') }}</template>
<div style="padding:0 32px 32px 32px;">
<ui-textarea :value="JSON.stringify(content, null, 2)" readonly tall>{{ $t('content') }}</ui-textarea>
<ui-textarea :value="JSON.stringify(variables, null, 2)" readonly tall>{{ $t('variables') }}</ui-textarea>
</div>
</ui-container>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import * as XDraggable from 'vuedraggable';
import { faICursor, faPlus, faMagic, faCog, faCode, faExternalLinkSquareAlt } from '@fortawesome/free-solid-svg-icons';
import { faSave, faStickyNote, faTrashAlt } from '@fortawesome/free-regular-svg-icons';
import i18n from '../../../../i18n';
import XVariable from './page-editor.script-block.vue';
import XBlocks from './page-editor.blocks.vue';
import * as uuid from 'uuid';
import { blockDefs } from '../../../../../../misc/aiscript/index';
import { ASTypeChecker } from '../../../../../../misc/aiscript/type-checker';
import { url } from '../../../../config';
import { collectPageVars } from '../../../scripts/collect-page-vars';
export default Vue.extend({
i18n: i18n('pages'),
components: {
XDraggable, XVariable, XBlocks
},
props: {
page: {
type: Object,
required: false
},
readonly: {
type: Boolean,
required: false,
default: false
},
},
data() {
return {
author: this.$store.state.i,
pageId: null,
currentName: null,
title: '',
summary: null,
name: Date.now().toString(),
eyeCatchingImage: null,
eyeCatchingImageId: null,
font: 'sans-serif',
content: [],
alignCenter: false,
variables: [],
aiScript: null,
showOptions: false,
moreDetails: false,
url,
faPlus, faICursor, faSave, faStickyNote, faMagic, faCog, faTrashAlt, faExternalLinkSquareAlt, faCode
};
},
watch: {
async eyeCatchingImageId() {
if (this.eyeCatchingImageId == null) {
this.eyeCatchingImage = null;
} else {
this.eyeCatchingImage = await this.$root.api('drive/files/show', {
fileId: this.eyeCatchingImageId,
});
}
},
},
created() {
this.aiScript = new ASTypeChecker();
this.$watch('variables', () => {
this.aiScript.variables = this.variables;
}, { deep: true });
this.$watch('content', () => {
this.aiScript.pageVars = collectPageVars(this.content);
}, { deep: true });
if (this.page) {
this.author = this.page.user;
this.pageId = this.page.id;
this.title = this.page.title;
this.name = this.page.name;
this.currentName = this.page.name;
this.summary = this.page.summary;
this.font = this.page.font;
this.alignCenter = this.page.alignCenter;
this.content = this.page.content;
this.variables = this.page.variables;
this.eyeCatchingImageId = this.page.eyeCatchingImageId;
} else {
const id = uuid.v4();
this.content = [{
id,
type: 'text',
text: 'Hello World!'
}];
}
},
provide() {
return {
readonly: this.readonly,
getScriptBlockList: this.getScriptBlockList,
getPageBlockList: this.getPageBlockList
}
},
methods: {
save() {
if (this.pageId) {
this.$root.api('pages/update', {
pageId: this.pageId,
title: this.title.trim(),
name: this.name.trim(),
summary: this.summary,
font: this.font,
alignCenter: this.alignCenter,
content: this.content,
variables: this.variables,
eyeCatchingImageId: this.eyeCatchingImageId,
}).then(page => {
this.currentName = this.name.trim();
this.$root.dialog({
type: 'success',
text: this.$t('page-updated')
});
});
} else {
this.$root.api('pages/create', {
title: this.title.trim(),
name: this.name.trim(),
summary: this.summary,
font: this.font,
alignCenter: this.alignCenter,
content: this.content,
variables: this.variables,
eyeCatchingImageId: this.eyeCatchingImageId,
}).then(page => {
this.pageId = page.id;
this.currentName = this.name.trim();
this.$root.dialog({
type: 'success',
text: this.$t('page-created')
});
this.$router.push(`/i/pages/edit/${this.pageId}`);
});
}
},
del() {
this.$root.dialog({
type: 'warning',
text: this.$t('are-you-sure-delete'),
showCancelButton: true
}).then(({ canceled }) => {
if (canceled) return;
this.$root.api('pages/delete', {
pageId: this.pageId,
}).then(() => {
this.$root.dialog({
type: 'success',
text: this.$t('page-deleted')
});
this.$router.push(`/i/pages`);
});
});
},
async add() {
const { canceled, result: type } = await this.$root.dialog({
type: null,
title: this.$t('choose-block'),
select: {
groupedItems: this.getPageBlockList()
},
showCancelButton: true
});
if (canceled) return;
const id = uuid.v4();
this.content.push({ id, type });
},
async addVariable() {
let { canceled, result: name } = await this.$root.dialog({
title: this.$t('enter-variable-name'),
input: {
type: 'text',
},
showCancelButton: true
});
if (canceled) return;
name = name.trim();
if (this.aiScript.isUsedName(name)) {
this.$root.dialog({
type: 'error',
text: this.$t('the-variable-name-is-already-used')
});
return;
}
const id = uuid.v4();
this.variables.push({ id, name, type: null });
},
removeVariable(v) {
const i = this.variables.findIndex(x => x.name === v.name);
const newValue = [
...this.variables.slice(0, i),
...this.variables.slice(i + 1)
];
this.variables = newValue;
},
getPageBlockList() {
return [{
label: this.$t('content-blocks'),
items: [
{ value: 'section', text: this.$t('blocks.section') },
{ value: 'text', text: this.$t('blocks.text') },
{ value: 'image', text: this.$t('blocks.image') },
{ value: 'textarea', text: this.$t('blocks.textarea') },
]
}, {
label: this.$t('input-blocks'),
items: [
{ value: 'button', text: this.$t('blocks.button') },
{ value: 'textInput', text: this.$t('blocks.textInput') },
{ value: 'textareaInput', text: this.$t('blocks.textareaInput') },
{ value: 'numberInput', text: this.$t('blocks.numberInput') },
{ value: 'switch', text: this.$t('blocks.switch') },
{ value: 'counter', text: this.$t('blocks.counter') }
]
}, {
label: this.$t('special-blocks'),
items: [
{ value: 'if', text: this.$t('blocks.if') },
{ value: 'post', text: this.$t('blocks.post') }
]
}];
},
getScriptBlockList(type: string = null) {
const list = [];
const blocks = blockDefs.filter(block => type === null || block.out === null || block.out === type || typeof block.out === 'number');
for (const block of blocks) {
const category = list.find(x => x.category === block.category);
if (category) {
category.items.push({
value: block.type,
text: this.$t(`script.blocks.${block.type}`)
});
} else {
list.push({
category: block.category,
label: this.$t(`script.categories.${block.category}`),
items: [{
value: block.type,
text: this.$t(`script.blocks.${block.type}`)
}]
});
}
}
const userFns = this.variables.filter(x => x.type === 'fn');
if (userFns.length > 0) {
list.unshift({
label: this.$t(`script.categories.fn`),
items: userFns.map(v => ({
value: 'fn:' + v.name,
text: v.name
}))
});
}
return list;
},
setEyeCatchingImage() {
this.$chooseDriveFile({
multiple: false
}).then(file => {
this.eyeCatchingImageId = file.id;
});
},
removeEyeCatchingImage() {
this.eyeCatchingImageId = null;
}
}
});
</script>
<style lang="stylus" scoped>
.gwbmwxkm
overflow hidden
background var(--face)
margin-bottom 16px
&.round
border-radius 6px
&.shadow
box-shadow 0 3px 8px rgba(0, 0, 0, 0.2)
> header
background var(--faceHeader)
> .title
z-index 1
margin 0
padding 0 16px
line-height 42px
font-size 0.9em
font-weight bold
color var(--faceHeaderText)
box-shadow 0 var(--lineWidth) rgba(#000, 0.07)
> [data-icon]
margin-right 6px
&:empty
display none
> .buttons
position absolute
z-index 2
top 0
right 0
> button
padding 0
width 42px
font-size 0.9em
line-height 42px
color var(--faceTextButton)
&:hover
color var(--faceTextButtonHover)
&:active
color var(--faceTextButtonActive)
> section
padding 0 32px 32px 32px
@media (max-width 500px)
padding 0 16px 16px 16px
> .view
display inline-block
margin 16px 0 0 0
font-size 14px
> .content
margin-bottom 16px
> .eyeCatch
margin-bottom 16px
> div
> img
max-width 100%
.qmuvgica
padding 32px
@media (max-width 500px)
padding 16px
> .variables
margin-bottom 16px
> .add
margin-bottom 16px
</style>

View File

@ -0,0 +1,141 @@
<template>
<router-link :to="`/@${page.user.username}/pages/${page.name}`" class="vhpxefrj" tabindex="-1" :class="{ shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners }">
<div class="thumbnail" v-if="page.eyeCatchingImage" :style="`background-image: url('${page.eyeCatchingImage.thumbnailUrl}')`"></div>
<article>
<header>
<h1 :title="page.title">{{ page.title }}</h1>
</header>
<p v-if="page.summary" :title="page.summary">{{ page.summary.length > 85 ? page.summary.slice(0, 85) + '…' : page.summary }}</p>
<footer>
<img class="icon" :src="page.user.avatarUrl"/>
<p>{{ page.user | userName }}</p>
</footer>
</article>
</router-link>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
props: {
page: {
type: Object,
required: true
},
},
});
</script>
<style lang="stylus" scoped>
.vhpxefrj
display block
overflow hidden
width 100%
background var(--face)
&.round
border-radius 8px
&.shadow
box-shadow 0 4px 16px rgba(#000, 0.1)
@media (min-width 500px)
box-shadow 0 8px 32px rgba(#000, 0.1)
> .thumbnail
position absolute
width 100px
height 100%
background-position center
background-size cover
display flex
justify-content center
align-items center
> button
font-size 3.5em
opacity: 0.7
&:hover
font-size 4em
opacity 0.9
& + article
left 100px
width calc(100% - 100px)
> article
padding 16px
> header
margin-bottom 8px
> h1
margin 0
font-size 1em
color var(--urlPreviewTitle)
> p
margin 0
color var(--urlPreviewText)
font-size 0.8em
> footer
margin-top 8px
height 16px
> img
display inline-block
width 16px
height 16px
margin-right 4px
vertical-align top
> p
display inline-block
margin 0
color var(--urlPreviewInfo)
font-size 0.8em
line-height 16px
vertical-align top
@media (max-width 700px)
> .thumbnail
position relative
width 100%
height 100px
& + article
left 0
width 100%
@media (max-width 550px)
font-size 12px
> .thumbnail
height 80px
> article
padding 12px
@media (max-width 500px)
font-size 10px
> .thumbnail
height 70px
> article
padding 8px
> header
margin-bottom 4px
> footer
margin-top 4px
> img
width 12px
height 12px
</style>

View File

@ -9,7 +9,7 @@
</template>
<div v-if="data && !$store.state.i.twoFactorEnabled">
<ol>
<li>{{ $t('authenticator') }}<a href="https://support.google.com/accounts/answer/1066447" target="_blank">{{ $t('howtoinstall') }}</a></li>
<li>{{ $t('authenticator') }}<a href="https://support.google.com/accounts/answer/1066447" rel="noopener" target="_blank">{{ $t('howtoinstall') }}</a></li>
<li>{{ $t('scan') }}<br><img :src="data.qr"></li>
<li>{{ $t('done') }}<br>
<ui-input v-model="token">{{ $t('token') }}</ui-input>

View File

@ -14,7 +14,7 @@
<section>
<header><fa icon="terminal"/> {{ $t('console.title') }}</header>
<ui-input v-model="endpoint" :datalist="endpoints">
<ui-input v-model="endpoint" :datalist="endpoints" @change="onEndpointChange()">
<span>{{ $t('console.endpoint') }}</span>
</ui-input>
<ui-textarea v-model="body">
@ -80,6 +80,22 @@ export default Vue.extend({
this.sending = false;
this.res = JSON5.stringify(err, null, 2);
});
},
onEndpointChange() {
this.$root.api('endpoint', { endpoint: this.endpoint }).then(endpoint => {
const body = {};
for (const p of endpoint.params) {
body[p.name] =
p.type === 'String' ? '' :
p.type === 'Number' ? 0 :
p.type === 'Boolean' ? false :
p.type === 'Array' ? [] :
p.type === 'Object' ? {} :
null;
}
this.body = JSON5.stringify(body, null, 2);
});
}
}
});

View File

@ -4,21 +4,21 @@
<section v-if="enableTwitterIntegration">
<header><fa :icon="['fab', 'twitter']"/> Twitter</header>
<p v-if="$store.state.i.twitter">{{ $t('connected-to') }}: <a :href="`https://twitter.com/${$store.state.i.twitter.screenName}`" target="_blank">@{{ $store.state.i.twitter.screenName }}</a></p>
<p v-if="$store.state.i.twitter">{{ $t('connected-to') }}: <a :href="`https://twitter.com/${$store.state.i.twitter.screenName}`" rel="nofollow noopener" target="_blank">@{{ $store.state.i.twitter.screenName }}</a></p>
<ui-button v-if="$store.state.i.twitter" @click="disconnectTwitter">{{ $t('disconnect') }}</ui-button>
<ui-button v-else @click="connectTwitter">{{ $t('connect') }}</ui-button>
</section>
<section v-if="enableDiscordIntegration">
<header><fa :icon="['fab', 'discord']"/> Discord</header>
<p v-if="$store.state.i.discord">{{ $t('connected-to') }}: <a :href="`https://discordapp.com/users/${$store.state.i.discord.id}`" target="_blank">@{{ $store.state.i.discord.username }}#{{ $store.state.i.discord.discriminator }}</a></p>
<p v-if="$store.state.i.discord">{{ $t('connected-to') }}: <a :href="`https://discordapp.com/users/${$store.state.i.discord.id}`" rel="nofollow noopener" target="_blank">@{{ $store.state.i.discord.username }}#{{ $store.state.i.discord.discriminator }}</a></p>
<ui-button v-if="$store.state.i.discord" @click="disconnectDiscord">{{ $t('disconnect') }}</ui-button>
<ui-button v-else @click="connectDiscord">{{ $t('connect') }}</ui-button>
</section>
<section v-if="enableGithubIntegration">
<header><fa :icon="['fab', 'github']"/> GitHub</header>
<p v-if="$store.state.i.github">{{ $t('connected-to') }}: <a :href="`https://github.com/${$store.state.i.github.login}`" target="_blank">@{{ $store.state.i.github.login }}</a></p>
<p v-if="$store.state.i.github">{{ $t('connected-to') }}: <a :href="`https://github.com/${$store.state.i.github.login}`" rel="nofollow noopener" target="_blank">@{{ $store.state.i.github.login }}</a></p>
<ui-button v-if="$store.state.i.github" @click="disconnectGithub">{{ $t('disconnect') }}</ui-button>
<ui-button v-else @click="connectGithub">{{ $t('connect') }}</ui-button>
</section>
@ -54,7 +54,11 @@ export default Vue.extend({
},
mounted() {
document.cookie = `i=${this.$store.state.i.token}`;
if (!document.cookie.match(/i=(\w+)/)) {
document.cookie = `i=${this.$store.state.i.token}; path=/;` +
` domain=${document.location.hostname}; max-age=31536000;` +
(document.location.protocol.startsWith('https') ? ' secure' : '');
}
this.$watch('$store.state.i', () => {
if (this.$store.state.i.twitter) {
if (this.twitterForm) this.twitterForm.close();

View File

@ -290,12 +290,17 @@ export default Vue.extend({
this.exportTarget == 'mute' ? 'i/export-mute' :
this.exportTarget == 'blocking' ? 'i/export-blocking' :
this.exportTarget == 'user-lists' ? 'i/export-user-lists' :
null, {});
this.$root.dialog({
type: 'info',
text: this.$t('export-requested')
});
null, {}).then(() => {
this.$root.dialog({
type: 'info',
text: this.$t('export-requested')
});
}).catch((e: any) => {
this.$root.dialog({
type: 'error',
text: e.message
});
});
},
doImport() {

View File

@ -543,8 +543,8 @@ export default Vue.extend({
});
} else {
this.$root.dialog({
title: this.$t('update-available'),
text: this.$t('update-available-desc')
title: this.$t('@._settings.update-available'),
text: this.$t('@._settings.update-available-desc')
});
}
});

View File

@ -45,7 +45,7 @@
</ui-select>
</label>
<a href="https://assets.msky.cafe/theme/list" target="_blank">{{ $t('find-more-theme') }}</a>
<a href="https://assets.msky.cafe/theme/list" rel="noopener" target="_blank">{{ $t('find-more-theme') }}</a>
<details class="creator">
<summary><fa icon="palette"/> {{ $t('create-a-theme') }}</summary>
@ -273,7 +273,7 @@ export default Vue.extend({
import_() {
(this.$refs.file as any).click();
}
},
export_() {
const blob = new Blob([this.selectedThemeCode], {

View File

@ -10,14 +10,14 @@
<span>{{ $t('password') }}</span>
<template #prefix><fa icon="lock"/></template>
</ui-input>
<ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="number" required>
<ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="text" pattern="^[0-9]{6}$" autocomplete="off" spellcheck="false" required>
<span>{{ $t('@.2fa') }}</span>
<template #prefix><fa icon="gavel"/></template>
</ui-input>
<ui-button type="submit" :disabled="signing">{{ signing ? $t('signing-in') : $t('@.signin') }}</ui-button>
<p v-if="meta && meta.enableTwitterIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/twitter`">{{ $t('signin-with-twitter') }}</a></p>
<p v-if="meta && meta.enableGithubIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/github`">{{ $t('signin-with-github') }}</a></p>
<p v-if="meta && meta.enableDiscordIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/discord`">{{ $t('signin-with-discord') /* TODO: Make these layouts better */ }}</a></p>
<p v-if="meta && meta.enableTwitterIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/twitter`"><fa :icon="['fab', 'twitter']"/> {{ $t('signin-with-twitter') }}</a></p>
<p v-if="meta && meta.enableGithubIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/github`"><fa :icon="['fab', 'github']"/> {{ $t('signin-with-github') }}</a></p>
<p v-if="meta && meta.enableDiscordIntegration" style="margin: 8px 0;"><a :href="`${apiUrl}/signin/discord`"><fa :icon="['fab', 'discord']"/> {{ $t('signin-with-discord') /* TODO: Make these layouts better */ }}</a></p>
</form>
</template>

View File

@ -37,8 +37,13 @@
<p v-if="passwordRetypeState == 'not-match'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> {{ $t('password-not-matched') }}</p>
</template>
</ui-input>
<ui-switch v-model="ToSAgreement" v-if="meta.ToSUrl">
<i18n path="agree-to">
<a :href="meta.ToSUrl" target="_blank">{{ $t('tos') }}</a>
</i18n>
</ui-switch>
<div v-if="meta.enableRecaptcha" class="g-recaptcha" :data-sitekey="meta.recaptchaSiteKey" style="margin: 16px 0;"></div>
<ui-button type="submit">{{ $t('create') }}</ui-button>
<ui-button type="submit" :disabled="!(meta.ToSUrl ? ToSAgreement : true)">{{ $t('create') }}</ui-button>
</template>
</form>
</template>
@ -64,7 +69,8 @@ export default Vue.extend({
usernameState: null,
passwordStrength: '',
passwordRetypeState: null,
meta: null
meta: {},
ToSAgreement: false
}
},

View File

@ -4,7 +4,7 @@
<p class="empty" v-else-if="tags.length == 0"><fa icon="exclamation-circle"/>{{ $t('empty') }}</p>
<div v-else>
<vue-word-cloud
:words="tags.slice(0, 20).map(x => [x.name, x.count])"
:words="tags.slice(0, 20).map(x => [x.tag, x.count])"
:color="color"
:spacing="1">
<template slot-scope="{word, text, weight}">
@ -43,7 +43,7 @@ export default Vue.extend({
},
methods: {
fetch() {
this.$root.api('aggregation/hashtags').then(tags => {
this.$root.api('hashtags/trend').then(tags => {
this.tags = tags;
this.fetching = false;
});

View File

@ -1,7 +1,7 @@
<template>
<component class="dmtdnykelhudezerjlfpbhgovrgnqqgr"
:is="link ? 'a' : 'button'"
:class="{ inline, primary, wait }"
:class="{ inline, primary, wait, round: $store.state.device.roundedCorners }"
:type="type"
@click="$emit('click')"
@mousedown="onMousedown"
@ -116,7 +116,6 @@ export default Vue.extend({
font-size 16px
line-height 24px
border none
border-radius 6px
outline none
box-shadow none
text-decoration none
@ -124,6 +123,9 @@ export default Vue.extend({
color var(--text)
background var(--buttonBg)
&.round
border-radius 6px
&:not(:disabled):hover
background var(--buttonHoverBg)
@ -157,7 +159,9 @@ export default Vue.extend({
bottom -5px
left -5px
border 2px solid var(--primaryAlpha03)
border-radius 10px
&.round:focus:after
border-radius 10px
&:not(.inline) + .dmtdnykelhudezerjlfpbhgovrgnqqgr
margin-top 16px
@ -197,7 +201,6 @@ export default Vue.extend({
left 0
width 100%
height 100%
border-radius 6px
overflow hidden
>>> div
@ -210,6 +213,9 @@ export default Vue.extend({
transform scale(1)
transition all 0.5s cubic-bezier(0, .5, .5, 1)
&.round > .ripples
border-radius 6px
&.primary > .ripples >>> div
background rgba(0, 0, 0, 0.15)

View File

@ -23,6 +23,7 @@
@focus="focused = true"
@blur="focused = false"
@keydown="$emit('keydown', $event)"
@change="$emit('change', $event)"
:list="id"
>
<input v-else ref="input"
@ -38,6 +39,7 @@
@focus="focused = true"
@blur="focused = false"
@keydown="$emit('keydown', $event)"
@change="$emit('change', $event)"
:list="id"
>
<datalist :id="id" v-if="datalist">
@ -60,7 +62,7 @@
<div class="suffix" ref="suffix"><slot name="suffix"></slot></div>
</div>
<div class="toggle" v-if="withPasswordToggle">
<a @click='togglePassword'>
<a @click="togglePassword">
<span v-if="type == 'password'"><fa :icon="['fa', 'eye']"/> {{ $t('@.show-password') }}</span>
<span v-if="type != 'password'"><fa :icon="['far', 'eye-slash']"/> {{ $t('@.hide-password') }}</span>
</a>
@ -182,7 +184,11 @@ export default Vue.extend({
this.v = v;
},
v(v) {
this.$emit('input', v);
if (this.type === 'number') {
this.$emit('input', parseInt(v, 10));
} else {
this.$emit('input', v);
}
if (this.withPasswordMeter) {
if (v == '') {
@ -316,7 +322,7 @@ root(fill)
> .value
display block
width 0%
width 0
height 100%
background transparent
border-radius 6px

View File

@ -5,10 +5,9 @@
<span class="label" ref="label"><slot name="label"></slot></span>
<div class="prefix" ref="prefix"><slot name="prefix"></slot></div>
<select ref="input"
:value="v"
v-model="v"
:required="required"
:disabled="disabled"
@input="$emit('input', $event.target.value)"
@focus="focused = true"
@blur="focused = false"
>
@ -56,20 +55,22 @@ export default Vue.extend({
},
data() {
return {
v: this.value,
focused: false
};
},
computed: {
v: {
get() {
return this.value;
},
set(v) {
this.$emit('input', v);
}
},
filled(): boolean {
return this.v != '' && this.v != null;
}
},
watch: {
value(v) {
this.v = v;
}
},
mounted() {
if (this.$refs.prefix) {
this.$refs.label.style.left = (this.$refs.prefix.offsetLeft + this.$refs.prefix.offsetWidth) + 'px';

View File

@ -38,10 +38,10 @@ export default Vue.extend({
const data = new FormData();
data.append('md5', getMD5(fileData));
this.$root.api('drive/files/check_existence', {
this.$root.api('drive/files/find-by-hash', {
md5: getMD5(fileData)
}).then(resp => {
resolve(resp.file);
resolve(resp.length > 0 ? resp[0] : null);
});
});
},

View File

@ -9,7 +9,7 @@
</blockquote>
</div>
<div v-else class="mk-url-preview">
<a :class="{ mini: narrow, compact }" :href="url" target="_blank" :title="url" v-if="!fetching">
<a :class="{ mini: narrow, compact }" :href="url" rel="nofollow noopener" target="_blank" :title="url" v-if="!fetching">
<div class="thumbnail" v-if="thumbnail" :style="`background-image: url('${thumbnail}')`">
<button v-if="!playerEnabled && player.url" @click.prevent="playerEnabled = true" :title="$t('enable-player')"><fa :icon="['far', 'play-circle']"/></button>
</div>

View File

@ -1,5 +1,5 @@
<template>
<a class="mk-url" :href="url" :target="target">
<a class="mk-url" :href="url" :rel="rel" :target="target">
<span class="schema">{{ schema }}//</span>
<span class="hostname">{{ hostname }}</span>
<span class="port" v-if="port != ''">:{{ port }}</span>
@ -15,7 +15,7 @@ import Vue from 'vue';
import { toUnicode as decodePunycode } from 'punycode';
export default Vue.extend({
props: ['url', 'target'],
props: ['url', 'rel', 'target'],
data() {
return {
schema: null,

View File

@ -77,11 +77,11 @@ export default Vue.extend({
input: {
default: this.list.name
}
}).then(({ canceled, result: title }) => {
}).then(({ canceled, result: name }) => {
if (canceled) return;
this.$root.api('users/lists/update', {
listId: this.list.id,
title: title
name: name
});
});
},

View File

@ -60,9 +60,9 @@ export default Vue.extend({
},
methods: {
init() {
async init() {
this.fetching = true;
this.makePromise().then(x => {
await (this.makePromise()).then(x => {
if (Array.isArray(x)) {
this.us = x;
} else {
@ -76,9 +76,9 @@ export default Vue.extend({
});
},
fetchMoreUsers() {
async fetchMoreUsers() {
this.fetchingMoreUsers = true;
this.makePromise(this.cursor).then(x => {
await (this.makePromise(this.cursor)).then(x => {
this.us = this.us.concat(x.users);
this.cursor = x.cursor;
this.fetchingMoreUsers = false;
@ -166,7 +166,7 @@ export default Vue.extend({
> .follow-button
position absolute
top 8px
right 0px
right 0
> .more
display block

View File

@ -28,10 +28,10 @@ export default Vue.extend({
this.$root.dialog({
title: this.$t('list-name'),
input: true
}).then(async ({ canceled, result: title }) => {
}).then(async ({ canceled, result: name }) => {
if (canceled) return;
const list = await this.$root.api('users/lists/create', {
title
name
});
this.lists.push(list)

View File

@ -7,7 +7,6 @@
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
import copyToClipboard from '../../../common/scripts/copy-to-clipboard';
import { faExclamationCircle, faMicrophoneSlash } from '@fortawesome/free-solid-svg-icons';
import { faSnowflake } from '@fortawesome/free-regular-svg-icons';
@ -27,19 +26,23 @@ export default Vue.extend({
icon: ['fas', 'list'],
text: this.$t('push-to-list'),
action: this.pushList
}, null, {
icon: this.user.isMuted ? ['fas', 'eye'] : ['far', 'eye-slash'],
text: this.user.isMuted ? this.$t('unmute') : this.$t('mute'),
action: this.toggleMute
}, {
icon: 'ban',
text: this.user.isBlocking ? this.$t('unblock') : this.$t('block'),
action: this.toggleBlock
}, null, {
icon: faExclamationCircle,
text: this.$t('report-abuse'),
action: this.reportAbuse
}];
}] as any;
if (this.$store.getters.isSignedIn && this.$store.state.i.id != this.user.id) {
menu = menu.concat([null, {
icon: this.user.isMuted ? ['fas', 'eye'] : ['far', 'eye-slash'],
text: this.user.isMuted ? this.$t('unmute') : this.$t('mute'),
action: this.toggleMute
}, {
icon: 'ban',
text: this.user.isBlocking ? this.$t('unblock') : this.$t('block'),
action: this.toggleBlock
}, null, {
icon: faExclamationCircle,
text: this.$t('report-abuse'),
action: this.reportAbuse
}]);
}
if (this.$store.getters.isSignedIn && (this.$store.state.i.isAdmin || this.$store.state.i.isModerator)) {
menu = menu.concat([null, {

View File

@ -160,7 +160,7 @@ export default Vue.extend({
this.$emit('top');
}
if (this.$store.state.settings.fetchOnScroll !== false) {
if (this.$store.state.settings.fetchOnScroll) {
const current = this.$refs.body.scrollTop + this.$refs.body.clientHeight;
if (current > this.$refs.body.scrollHeight - 1) this.$emit('bottom');
}

View File

@ -8,7 +8,7 @@
<div class="is-remote" v-if="note.user.host != null">
<details>
<summary><fa icon="exclamation-triangle"/> {{ $t('@.is-remote-post') }}</summary>
<a :href="note.url || note.uri" target="_blank">{{ $t('@.view-on-remote') }}</a>
<a :href="note.url || note.uri" rel="nofollow noopener" target="_blank">{{ $t('@.view-on-remote') }}</a>
</details>
</div>
<mk-note :note="note" :detail="true" :key="note.id"/>

View File

@ -110,11 +110,11 @@ export default Vue.extend({
this.init();
},
init() {
async init() {
this.queue = [];
this.notes = [];
this.fetching = true;
this.makePromise().then(x => {
await (this.makePromise()).then(x => {
if (Array.isArray(x)) {
this.notes = x;
} else {
@ -129,10 +129,10 @@ export default Vue.extend({
});
},
fetchMore() {
async fetchMore() {
if (!this.more || this.moreFetching) return;
this.moreFetching = true;
this.makePromise(this.notes[this.notes.length - 1].id).then(x => {
await (this.makePromise(this.notes[this.notes.length - 1].id)).then(x => {
this.notes = this.notes.concat(x.notes);
this.more = x.more;
this.moreFetching = false;

View File

@ -14,6 +14,7 @@
import Vue from 'vue';
import XColumn from './deck.column.vue';
import XNotes from './deck.notes.vue';
import { genSearchQuery } from '../../../common/scripts/gen-search-query';
const limit = 20;
@ -25,10 +26,10 @@ export default Vue.extend({
data() {
return {
makePromise: cursor => this.$root.api('notes/search', {
makePromise: async cursor => this.$root.api('notes/search', {
limit: limit + 1,
offset: cursor ? cursor : undefined,
query: this.q
...(await genSearchQuery(this, this.q))
}).then(notes => {
if (notes.length == limit + 1) {
notes.pop();

Some files were not shown because too many files have changed in this diff Show More