Compare commits

...

91 Commits

Author SHA1 Message Date
786521eba7 Merge branch 'develop' 2019-05-20 00:12:42 +09:00
202cb3048a 11.17.1 2019-05-20 00:12:19 +09:00
7e642cf700 Fix bug 2019-05-19 23:42:18 +09:00
7732aabc1e Fix bug 2019-05-19 23:29:28 +09:00
1cf9f52eca Merge branch 'develop' 2019-05-19 21:02:32 +09:00
d1d5e10b72 11.17.0 2019-05-19 21:02:17 +09:00
c3fada264f Fix #4938 2019-05-19 20:57:05 +09:00
45eeb74b83 Fix #4948 2019-05-19 20:52:00 +09:00
b9a6e551cd Add unique index 2019-05-19 20:50:08 +09:00
c610e5ed9b Update note-favorite.ts 2019-05-19 20:48:10 +09:00
c2c2824e50 Fix bug 2019-05-19 20:47:41 +09:00
01fab09683 Fix #4945 2019-05-19 20:43:33 +09:00
e103904a04 Resolve #4941 2019-05-19 20:41:23 +09:00
56678cbac0 Update README.md [AUTOGEN] (#4940) 2019-05-19 15:08:16 +09:00
7fade8939d Merge branch 'develop' 2019-05-19 03:22:41 +09:00
daa557f6a3 11.16.1 2019-05-19 03:22:26 +09:00
23a257ed86 Update Dockerfile 2019-05-19 03:21:39 +09:00
05d0620491 Merge branch 'develop' 2019-05-19 02:51:49 +09:00
5225139284 11.16.0 2019-05-19 02:51:28 +09:00
9b2e996cae 🎨 2019-05-19 02:47:31 +09:00
6a561342a4 🎨 2019-05-19 02:39:34 +09:00
429bed2f91 Refactor 2019-05-18 23:16:09 +09:00
200d593414 Add group menu 2019-05-18 22:57:34 +09:00
9dbe12135d Fix bug 2019-05-18 22:54:02 +09:00
318d7f2652 🎨 2019-05-18 22:50:57 +09:00
5a653531e2 Avoid error 2019-05-18 21:22:37 +09:00
c7cc3dcdfd ユーザーグループ
Resolve #3218
2019-05-18 20:36:33 +09:00
61f54f8f74 Fix bug 2019-05-18 00:38:33 +09:00
a3b27fe3a1 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2019-05-17 19:56:56 +09:00
380749051d ページにいいねできるように 2019-05-17 19:56:47 +09:00
ql3
81625f9fc5 Update gitignore to ignore config files for Intelij-IDEA (#4933) 2019-05-17 02:31:00 +09:00
d6ccb1725b Update API docs 2019-05-17 00:19:23 +09:00
5ce412aeda Merge branch 'develop' 2019-05-16 16:14:00 +09:00
fe6d88e410 11.15.0 2019-05-16 16:13:46 +09:00
a21357248f Dockerを使用している場合、アプデの際にマイグレを自動実行するように 2019-05-16 16:12:30 +09:00
70d710c9a9 管理画面でreCAPTCHAのプレビューを表示するように 2019-05-16 16:08:50 +09:00
183c82fb8d New Crowdin translations (#4924)
* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (French)

* 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)

* New translations ja-JP.yml (English)

* 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 (Japanese, Kansai)

* 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)
2019-05-16 13:11:56 +09:00
62cbb92154 Fix #4930 2019-05-16 12:59:09 +09:00
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
188 changed files with 5441 additions and 1727 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 └───────────────────────────────────────────
@ -149,3 +108,6 @@ autoAdmin: true
# Clustering
#clusterLimit: 1
# IP address family used for outgoing request (ipv4, ipv6 or dual)
#outgoingAddressFamily: ipv4

19
.gitignore vendored
View File

@ -1,11 +1,23 @@
# Visual Studio Code
/.vscode
# Intelij-IDEA
/.idea
# Node.js
/node_modules
# yarn
yarn.lock
# config
/.config/*
!/.config/example.yml
!/.config/mongo_initdb_example.js
/.vscode
/node_modules
# misskey
/build
/built
built
/data
/.cache-loader
/db
@ -17,7 +29,6 @@ api-docs.json
*.log
/redis
*.code-workspace
yarn.lock
.DS_Store
/files
ormconfig.json

View File

@ -8,32 +8,13 @@ If you encounter any problems with updating, please try the following:
Migration
------------------------------
#### 1
`ormconfig.json`という名前で、Misskeyのインストール場所(package.jsonとかがあるディレクトリ)に新たなファイルを作る。中身は次のようにします:
``` json
{
"type": "postgres",
"host": "PostgreSQLのホスト",
"port": 5432,
"username": "PostgreSQLのユーザー名",
"password": "PostgreSQLのパスワード",
"database": "PostgreSQLのデータベース名",
"entities": ["src/models/entities/*.ts"],
"migrations": ["migration/*.ts"],
"cli": {
"migrationsDir": "migration"
}
}
```
上記の各種PostgreSQLの設定(ポートも)は、設定ファイルに書いてあるものをコピーしてください。
#### 2
```
npm i -g ts-node
```
#### 3
#### 2
```
ts-node ./node_modules/typeorm/cli.js migration:run
npm run migrate
```
How to migrate to v11 from v10
@ -73,21 +54,138 @@ mongodb:
8. master ブランチに戻す
9. enjoy
11.17.1 (2019/05/20)
--------------------
### 🐛Fixes
* トークの通知インジケーターが点灯し続ける問題を修正
* ユーザーグループの読み込みでエラーになることがある問題を修正
11.17.0 (2019/05/19)
--------------------
### 注意
このアップデートを適用した後、プロセスを起動(もしくは再起動)する前に[マイグレーション](#migration)の手順を実行してください
### ✨Improvements
* ユーザーグループを招待制に
### 🐛Fixes
* フォロー申請が表示されない問題を修正
* トークの通知インジケーターが点灯し続ける問題を修正
* 自分を自分のグループから削除できる問題を修正
* 新しいタブでグループトークを開くことができない問題を修正
11.16.1 (2019/05/19)
--------------------
### 🐛Fixes
* Dockerで起動できない問題を修正
11.16.0 (2019/05/19)
--------------------
### 注意
このアップデートを適用した後、プロセスを起動(もしくは再起動)する前に[マイグレーション](#migration)の手順を実行してください
### ✨Improvements
* ユーザーグループ機能を追加
* ページに「いいね」できるように
* UIの改善
### 🐛Fixes
* トークを読み込むときに最大数指定できなかった問題を修正
11.15.0 (2019/05/16)
--------------------
### ✨Improvements
* 管理画面でreCAPTCHAのプレビューを表示するように
### 🐛Fixes
* オブジェクトストレージのリージョンの設定が反映されない問題を修正
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
### Improvements
* MisskeyPagesにリストから選択関数を追加
* MisskeyPagesに確率を指定できるテキストランダム選択関数を追加
* 外部サービス連携ログインリンクにアイコン追加
### Fixes
### 🐛Fixes
* MisskeyPagesでifを入れ子にできなくなっていた問題を修正
* MisskeyPagesで数値入力を作成するとテキスト入力になる問題を修正
* 外部サービス連携に関する問題を修正
11.10.1 (2019/05/04)
--------------------
### Fixes
### 🐛Fixes
* MisskeyPagesでページブロックを削除できなくなっていた問題を修正
### その他
@ -98,13 +196,13 @@ mongodb:
### 注意
このアップデートを適用した後、プロセスを起動(もしくは再起動)する前に[マイグレーション](#migration)の手順を実行してください
### Improvements
### Improvements
* MisskeyPagesに割った余りを求める関数を追加
* Mastodon v2.8.0 のフォローリストをインポートできるように
* エクスポートリクエストに失敗したらエラーを表示するように
* エクスポートファイルでは同一ハッシュチェックをしないように
### Fixes
### 🐛Fixes
* 2段階認証を設定するとログインできなくなる問題を修正
* ファイルをアップロードできないことがある問題を修正
* リモートファイルをキャッシュしない設定だとサムネイル時にオリジナル画像が表示されない問題を修正
@ -112,13 +210,13 @@ mongodb:
11.9.0 (2019/05/02)
-------------------
### Improvements
### Improvements
* MisskeyPagesで編集時にページブロックをドラッグで並べ替えられるように
* MisskeyPagesにカウンターボタンブロックを追加
11.8.1 (2019/05/02)
-------------------
### Fixes
### 🐛Fixes
* リモートファイルをキャッシュしないオプション有効時にファイルが作成できない問題を修正
11.8.0-2 (2019/05/01)
@ -127,20 +225,20 @@ mongodb:
11.8.0 (2019/05/01)
-------------------
### Improvements
### Improvements
* MisskeyPagesで関数を作成できるように
* MisskeyPagesでソースを表示できるように
* MisskeyPagesにシードを与えるランダム関数を追加
* MisskeyPagesに複数行テキストをテキストのリストに変換する関数を追加
### Fixes
### 🐛Fixes
* APIドキュメントが見れなくなっていたのを修正
* mention (あなた宛て) streaming にミュートが効かない問題を修正
* デザインの調整
11.7.0 (2019/04/30)
-------------------
### Improvements
### Improvements
* MisskeyPagesに ifブロック を追加
* MisskeyPagesに テキストエリア を追加
* MisskeyPagesに 複数行テキスト入力 を追加
@ -149,23 +247,23 @@ mongodb:
* MisskeyPagesに 環境変数 URL を追加
* MisskeyPagesでボタンやスイッチなどのテキストに変数使えるように
### Fixes
### 🐛Fixes
* OGPのサイト名を修正
* デザインの調整
11.6.0 (2019/04/29)
-------------------
### Improvements
### Improvements
* AiScriptにいくつかの文字列操作関数を追加
* ページ編集画面にページへのリンクを表示するように
### Fixes
### 🐛Fixes
* MisskeyPagesで数値入力が文字列として扱われる問題を修正
* デザインの調整
11.5.1 (2019/04/29)
-------------------
### Fixes
### 🐛Fixes
* MisskeyPagesで環境変数を別の変数内で使えない問題を修正
* MisskeyPagesで値が0の変数が表示されない問題を修正
@ -191,21 +289,21 @@ mongodb:
ページを気に入ったら「いいね」しよう (coming soon)
### Improvements
### Improvements
* APIコンソールでパラメータテンプレートを表示するように
### Fixes
### 🐛Fixes
* おすすめユーザーに自分自身が含まれる問題を修正
* ユーザーサジェストで表示名が変わらない問題を修正
11.4.0 (2019/04/25)
-------------------
### Improvements
### Improvements
* 検索でローカルの投稿のみに絞れるように
* 検索で特定のインスタンスの投稿のみに絞れるように
* 検索で特定のユーザーの投稿のみに絞れるように
### Fixes
### 🐛Fixes
* 投稿が増殖する問題を修正
* ストリームで過去の投稿が流れてくる問題を修正
* モバイル版のユーザーページで遷移してもユーザー名が変わらない問題を修正
@ -213,43 +311,43 @@ mongodb:
11.3.1 (2019/04/24)
-------------------
### Fixes
### 🐛Fixes
* Webからファイルがアップロードできない問題を修正
11.3.0 (2019/04/24)
-------------------
### Improvements
### Improvements
* お知らせにMFMを使えるように
* お知らせに画像を添付できるように
### Fixes
### 🐛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に流れてくる問題を修正
@ -258,7 +356,7 @@ mongodb:
11.1.6 (2019/04/18)
-------------------
### Fixes
### 🐛Fixes
* 未認知ユーザーからActivityが飛んできた場合に処理できない問題を修正
* その投稿を見たのにも関わらずメンションインジケーターが点灯し続ける問題を修正
* ハッシュタグの判定を改善
@ -266,14 +364,14 @@ mongodb:
11.1.5 (2019/04/17)
-------------------
### Fixes
### 🐛Fixes
* ユーザー名に含まれているカスタム絵文字が表示されないことがある問題を修正
* 壁紙の設定ができない問題を修正
* デザインの調整
11.1.4 (2019/04/17)
-------------------
### Fixes
### 🐛Fixes
* タイムライン取得時に削除されたファイルを添付している投稿が含まれているとサーバーでエラーになる問題を修正
* 管理画面のインスタンスメニューで変更前の設定が読み込まれないことがある問題を修正
* 猫ではないのに猫のままで表示される問題を修正
@ -283,12 +381,12 @@ mongodb:
11.1.3 (2019/04/16)
-------------------
### Fixes
### 🐛Fixes
* アプリからAPIにリクエストするときにランダムなユーザーがリクエストしたことになる問題を修正
11.1.2 (2019/04/15)
-------------------
### Fixes
### 🐛Fixes
* 画像描画の依存関係を変更
* リモートユーザーのファイルを削除するときに古い方からではなく新しい方から削除されるのを修正
* リアクションしてないのにリアクションしたことになる問題を修正
@ -296,25 +394,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が動作しない問題を修正
* モデレーターなのにアカウントメニューに「管理」が表示されない問題を修正
* プッシュ通知の購読に失敗する問題を修正
@ -322,7 +420,7 @@ mongodb:
11.0.2 (2019/04/15)
-------------------
### Fixes
### 🐛Fixes
* アプリが作成できない問題を修正
* 「ハイライト」が表示されない問題を修正
* リモートの投稿に添付されている画像が小さい問題を修正
@ -331,19 +429,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

@ -39,4 +39,4 @@ COPY --from=builder /misskey/node_modules ./node_modules
COPY --from=builder /misskey/built ./built
COPY . ./
CMD ["npm", "start"]
CMD ["npm", "run", "migrateandstart"]

View File

@ -105,6 +105,7 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
<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="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>
@ -112,6 +113,7 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
</tr><tr>
<td><a href="https://www.patreon.com/rane_hs">Hiroshi Seki</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>
@ -127,7 +129,6 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
<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/2.jpeg?token-time=2145916800&token-hash=_sTj3dUBOhn9qwiJ7F19Qd-yWWfUqJC_0jG1h0agEqQ%3D" alt="sheeta.s" 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>
</tr><tr>
<td><a href="https://www.patreon.com/Yuzulia">YuzuRyo61</a></td>
<td><a href="https://www.patreon.com/gutfuckllc">gutfuckllc</a></td>
@ -138,38 +139,43 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
<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">sheeta.s</a></td>
<td><a href="https://www.patreon.com/user?u=13737140">Satsuki Yanagi</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/10789744/97175095d8f04c0f86225ff47cb98d40/1.jpeg?token-time=2145916800&token-hash=l4AoMR7Nj7K4yAHrkrk2hAoggPkbSPm12m1nmbe9Pb8%3D" alt="Naoki Hirayama" 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>
</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/spinlock">Naoki Hirayama</a></td>
<td><a href="https://www.patreon.com/dansup">dansup</a></td>
<td><a href="https://www.patreon.com/mastodon">Gargron</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:** Fri, 03 May 2019 05:33:07 UTC
**Last updated:** Sun, 19 May 2019 02:37: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é"
@ -853,7 +873,6 @@ admin/views/index.vue:
users: "Uživatelé"
federation: "Z fedivesmíru"
announcements: "Oznámení"
hashtags: "Hashtagy"
queue: "Fronta úloh"
logs: "Logy"
back-to-misskey: "Zpět na Misskey"
@ -878,6 +897,7 @@ admin/views/instance.vue:
maintainer-config: "Informace o administrátorovi"
maintainer-name: "Jméno administrátora"
maintainer-email: "Kontakt na administrátora"
object-storage-endpoint: "Endpoint"
mb: "V megabajtech"
recaptcha-config: "nastavení služby reCAPTCHA"
recaptcha-info: "reCAPTCHA token je povinný. Můžete jej získat na https://www.google.com/recaptcha/intro/"
@ -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"
@ -1062,7 +1063,6 @@ admin/views/index.vue:
users: "Users"
federation: "Federation"
announcements: "Announcements"
hashtags: "Hashtags"
abuse: "Abuse"
queue: "Job Queue"
logs: "Logs"
@ -1097,6 +1097,7 @@ admin/views/instance.vue:
maintainer-name: "Administrator name"
maintainer-email: "Contact Administrator"
drive-config: "Drive settings"
object-storage-endpoint: "Endpoint"
cache-remote-files: "Cache remote files"
cache-remote-files-desc: "Without this parameter, all remote files are linked to their host server directly. This will be an effective solution to save your server storage, however make remote files invisible to users who set direct-link disabled, since no thumbnail will be generated, increase traffic. It is recommended that this parameter set enabled."
local-drive-capacity-mb: "Volume of Drive per user"
@ -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,45 @@ admin/views/index.vue:
instance: "Instancia"
moderators: "Moderadores"
users: "Usuarios"
hashtags: "Hashtags"
federation: "Federado"
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 +976,6 @@ admin/views/users.vue:
state:
all: "Todo"
moderator: "Moderadores"
verified: "Cuenta verificada"
origin:
local: "Local"
admin/views/emoji.vue:
@ -846,12 +987,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 +1002,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 +1113,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

@ -60,6 +60,7 @@ common:
month-and-day: "{day}-{month}"
trash: "Corbeille"
drive: "Drive"
pages: "Pages"
messaging: "Conversations"
home: "Principal"
deck: "Deck"
@ -67,16 +68,22 @@ common:
explore: "Découvrir"
following: "Suit"
followers: "Abonné·e·s"
favorites: "Mettre cette note en favoris"
favorites: "Favorites"
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."
@ -132,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"
@ -192,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"
@ -233,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."
@ -301,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"
@ -454,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"
@ -472,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"
@ -556,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:
@ -1034,7 +1046,6 @@ admin/views/index.vue:
users: "Utilisateurs"
federation: "Fédération"
announcements: "Annonces"
hashtags: "Hashtags"
abuse: "Abus"
queue: "File dattente"
logs: "Journaux"
@ -1061,14 +1072,19 @@ admin/views/instance.vue:
instance-name: "Nom de linstance"
instance-description: "Description de linstance"
host: "Hôte"
icon-url: "URL de l'icône"
logo-url: "URL do logo"
banner-url: "URL de limage de la bannière"
error-image-url: "URL de limage derreur"
languages: "Langue de linstance"
languages-desc: "Vous pouvez en définir plus dune, séparées par des espaces."
tos-url: "URL des conditions d'utilisation"
repository-url: "URL du dépôt"
maintainer-config: "Informations de ladministrateur"
maintainer-name: "Nom de ladministrateur"
maintainer-email: "Contact administratif"
drive-config: "Paramètres du lecteur"
object-storage-endpoint: "Point de terminaison"
cache-remote-files: "Mettre en cache des fichiers distants"
local-drive-capacity-mb: "Volume du lecteur par utilisateur"
remote-drive-capacity-mb: "Volume du lecteur par utilisateur distant"
@ -1105,7 +1121,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"
@ -1186,13 +1201,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:
@ -1209,7 +1219,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:
@ -1308,6 +1317,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é"
@ -1468,7 +1478,11 @@ mobile/views/components/ui.nav.vue:
mobile/views/pages/drive.vue:
contextmenu:
upload: "Téléverser un fichier"
url-upload: "Transférer un fichier depuis une URL"
create-folder: "Créer un dossier"
rename-folder: "Renommer le dossier"
move-folder: "Déplacer ce dossier"
delete-folder: "Supprimer ce dossier"
mobile/views/pages/user-lists.vue:
title: "Listes"
mobile/views/pages/signup.vue:
@ -1570,25 +1584,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:
@ -1596,6 +1591,7 @@ dev/views/apps.vue:
create-app: "Créer une app"
app-missing: "Aucune application"
dev/views/new-app.vue:
new-app: "Nouvelle application"
create-app: "Création dune application"
app-name: "Nom de lapplication"
app-name-desc: "Le nom de votre application"
@ -1605,3 +1601,182 @@ 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"
input-blocks: "Entrée"
special-blocks: "Spécial"
post-from-post-form: "Publier ce contenu"
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"
inc: "Augmenter le chiffre"
_button:
text: "Titre"
action: "L'opération lorsque le bouton sera pressé"
_action:
dialog: "Afficher une fenêtre de dialogue"
_dialog:
content: "Contenu"
resetRandom: "Réinitialiser le nombre aléatoire"
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"
_seedRannum:
arg2: "Min"
arg3: "Max"
_seedRandomPick:
arg2: "Listes"
pick: "Sélectionner dans la liste"
_pick:
arg1: "Listes"
arg2: "Position"
number: "Numérique"
stringToNumber: "Chaîne en chiffres"
_stringToNumber:
arg1: "Texte"
numberToString: "Chiffres en chaîne"
_numberToString:
arg1: "Numérique"
_splitStrByLine:
arg1: "Texte"
ref: "Variables"
fn: "Fonction"
_fn:
slots: "Emplacement"
arg1: "Sortie"
for: "Répéter"
types:
string: "Texte"
number: "Numérique"
array: "Listes"
stringArray: "Liste de texte"
enviromentVariables: "Variables d'environnement"

View File

@ -263,9 +263,9 @@ common:
update-available-title: "更新があります"
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
verified-user: "公式アカウント"
hide-password: "パスワードを隠す"
show-password: "パスワードを表示する"
enter-username: "ユーザー名を入力してください"
do-not-use-in-production: "これは開発ビルドです。本番環境で使用しないでください。"
user-suspended: "このユーザーは凍結されています。"
@ -339,7 +339,7 @@ auth/views/index.vue:
sign-in: "サインインしてください"
common/views/pages/explore.vue:
verified-users: "公式アカウント"
pinned-users: "ピン留めされたユーザー"
popular-users: "人気のユーザー"
recently-updated-users: "最近投稿したユーザー"
recently-registered-users: "新規ユーザー"
@ -481,20 +481,25 @@ common/views/components/messaging.vue:
search-user: "ユーザーを探す"
you: "あなた"
no-history: "履歴はありません"
user: "ユーザー"
group: "グループ"
start-with-user: "ユーザーとトークを開始"
start-with-group: "グループとトークを開始"
select-group: "グループを選択してください"
common/views/components/messaging-room.vue:
empty: "このユーザーと話したことはありません"
not-talked-user: "このユーザーとの会話はありません"
not-talked-group: "このグループでの会話はありません"
no-history: "これより過去の履歴はありません"
resize-form: "ドラッグしてフォームの広さを調整"
new-message: "新しいメッセージがあります"
only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
only-one-file-attached: "メッセージに添付できるファイルはひとつです"
common/views/components/messaging-room.form.vue:
input-message-here: "ここにメッセージを入力"
send: "送信"
attach-from-local: "PCからファイルを添付する"
attach-from-drive: "ドライブからファイルを添付する"
only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
only-one-file-attached: "メッセージに添付できるファイルはひとつです"
common/views/components/messaging-room.message.vue:
is-read: "既読"
@ -509,6 +514,7 @@ common/views/components/nav.vue:
repository: "リポジトリ"
develop: "開発者"
feedback: "フィードバック"
tos: "利用規約"
common/views/components/note-menu.vue:
mention: "メンション"
@ -629,6 +635,8 @@ common/views/components/signup.vue:
password-matched: "確認されました"
password-not-matched: "一致していません"
recaptcha: "認証"
agree-to: "{0}に同意します。"
tos: "利用規約"
create: "アカウント作成"
some-error: "何らかの原因によりアカウントの作成に失敗しました。再度お試しください。"
@ -748,11 +756,33 @@ common/views/components/user-list-editor.vue:
remove-user: "このリストから削除"
delete-are-you-sure: "リスト「$1」を削除しますか"
deleted: "削除しました"
add-user: "ユーザーを追加"
common/views/components/user-group-editor.vue:
users: "メンバー"
rename: "グループ名を変更"
delete: "グループを削除"
remove-user: "このグループから削除"
delete-are-you-sure: "グループ「$1」を削除しますか"
deleted: "削除しました"
invite: "招待"
invited: "招待を送信しました"
common/views/components/user-lists.vue:
user-lists: "リスト"
create-list: "リストを作成"
list-name: "リスト名"
common/views/components/user-groups.vue:
user-groups: "グループ"
create-group: "グループを作成"
group-name: "グループ名"
owned-groups: "自分のグループ"
joined-groups: "参加しているグループ"
invites: "招待"
accept-invite: "参加"
reject-invite: "拒否"
common/views/widgets/broadcast.vue:
fetching: "確認中"
no-broadcasts: "お知らせはありません"
@ -825,6 +855,11 @@ common/views/pages/follow.vue:
follow-processing: "フォロー処理中"
follow-request: "フォロー申請"
common/views/pages/follow-requests.vue:
received-follow-requests: "フォロー申請"
accept: "承認"
reject: "拒否"
desktop:
banner-crop-title: "バナーとして表示する部分を選択"
banner: "バナー"
@ -1137,6 +1172,7 @@ desktop/views/components/ui.header.vue:
desktop/views/components/ui.header.account.vue:
profile: "プロフィール"
lists: "リスト"
groups: "グループ"
follow-requests: "フォロー申請"
admin: "管理"
@ -1152,14 +1188,6 @@ desktop/views/components/ui.header.post.vue:
desktop/views/components/ui.header.search.vue:
placeholder: "検索"
desktop/views/components/received-follow-requests-window.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
desktop/views/components/user-lists-window.vue:
title: "リスト"
desktop/views/components/user-preview.vue:
notes: "投稿"
following: "フォロー"
@ -1185,7 +1213,6 @@ admin/views/index.vue:
users: "ユーザー"
federation: "連合"
announcements: "お知らせ"
hashtags: "ハッシュタグ"
abuse: "スパム報告"
queue: "ジョブキュー"
logs: "ログ"
@ -1216,14 +1243,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: "ローカルユーザーひとりあたりのドライブ容量"
@ -1232,8 +1279,12 @@ admin/views/instance.vue:
recaptcha-config: "reCAPTCHAの設定"
recaptcha-info: "reCAPTCHAを有効にする場合、reCAPTCHAトークンを取得する必要があります。https://www.google.com/recaptcha/intro/ にアクセスしてトークンを取得してください。"
enable-recaptcha: "reCAPTCHAを有効にする"
recaptcha-site-key: "reCAPTCHA site key"
recaptcha-secret-key: "reCAPTCHA secret key"
recaptcha-site-key: "サイトキー"
recaptcha-secret-key: "シークレットキー"
recaptcha-preview: "プレビュー"
hidden-tags: "非表示ハッシュタグ"
hidden-tags-info: "集計から除外するハッシュタグを改行で区切って記述します。"
external-service-integration-config: "外部サービス連携"
twitter-integration-config: "Twitter連携の設定"
twitter-integration-info: "コールバックURLは {url} に設定します。"
enable-twitter-integration: "Twitter連携を有効にする"
@ -1264,7 +1315,8 @@ admin/views/instance.vue:
invite: "招待"
save: "保存"
saved: "保存しました"
user-recommendation-config: "おすすめユーザー"
pinned-users: "ピン留めユーザー"
pinned-users-info: "ピン留めしたいユーザーを改行で区切って記述します。"
email-config: "メールサーバーの設定"
email-config-info: "メールアドレス確認やパスワードリセットの際に使われます。"
enable-email: "メール配信を有効にする"
@ -1351,14 +1403,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:
@ -1373,7 +1421,6 @@ admin/views/users.vue:
admin: "管理者"
moderator: "モデレーター"
adminOrModerator: "管理者+モデレーター"
verified: "公式アカウント"
silenced: "サイレンス済み"
suspended: "凍結済み"
origin:
@ -1440,6 +1487,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: "照会"
@ -1486,6 +1534,8 @@ admin/views/federation.vue:
chart-spans:
hour: "1時間ごと"
day: "1日ごと"
blocked-hosts: "ブロック"
blocked-hosts-info: "ブロックしたいホストを改行で区切って記述します。"
desktop/views/pages/welcome.vue:
about: "詳しく..."
@ -1676,6 +1726,7 @@ mobile/views/components/ui.nav.vue:
follow-requests: "フォロー申請"
search: "検索"
user-lists: "リスト"
user-groups: "グループ"
widgets: "ウィジェット"
game: "ゲーム"
admin: "管理"
@ -1690,9 +1741,6 @@ mobile/views/pages/drive.vue:
move-folder: "このフォルダを移動"
delete-folder: "このフォルダを削除"
mobile/views/pages/user-lists.vue:
title: "リスト"
mobile/views/pages/signup.vue:
lets-start: "📦 始めましょう"
@ -1725,11 +1773,6 @@ mobile/views/pages/widgets/activity.vue:
mobile/views/pages/share.vue:
share-with: "{name}で共有"
mobile/views/pages/received-follow-requests.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
mobile/views/pages/note.vue:
title: "投稿"
prev: "前の投稿"
@ -1850,6 +1893,10 @@ pages:
edit-this-page: "このページを編集"
view-source: "ソースを表示"
view-page: "ページを見る"
like: "いいね"
unlike: "いいね解除"
liked-pages: "いいねしたページ"
my-pages: "自分のページ"
inspector: "インスペクター"
content: "ページブロック"
variables: "変数"

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:
@ -838,7 +836,6 @@ admin/views/index.vue:
users: "ユーザー"
federation: "連合"
announcements: "知っといてや"
hashtags: "ハッシュタグ"
back-to-misskey: "Misskeyに戻る"
admin/views/dashboard.vue:
dashboard: "ダッシュボード"
@ -863,6 +860,7 @@ admin/views/instance.vue:
maintainer-name: "管理者名"
maintainer-email: "管理者の連絡先"
drive-config: "ドライブの設定"
object-storage-endpoint: "エンドポイント"
cache-remote-files: "リモートのファイルをキャッシュする"
cache-remote-files-desc: "この設定を無効にすると、リモートファイルをこっちで保管せずに直接リンク張るようになるで。サーバーのストレージは軽くやろうけど、プライバシー設定で直リンクを向こうにしとるユーザーはファイルが見れへんし、サムネイルが無いから通信量が増えたりするから、普通はオンにしといてな。"
local-drive-capacity-mb: "ローカルユーザーひとりあたりのドライブ容量"
@ -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: "사용중"
@ -1038,7 +1065,6 @@ admin/views/index.vue:
users: "사용자"
federation: "연합"
announcements: "공지사항"
hashtags: "해시태그"
abuse: "스팸 신고"
queue: "작업 대기열"
logs: "로그"
@ -1065,14 +1091,20 @@ 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: "관리자 연락처"
drive-config: "드라이브 설정"
object-storage-endpoint: "엔드포인트"
cache-remote-files: "원격 파일을 캐시"
cache-remote-files-desc: "이 설정을 해지하면 원격 파일을 캐시하지 않고 해당 파일을 직접 링크하게 됩니다. 그에 따라 서버의 저장 공간을 절약할 수 있지만, 프라이버시 설정에서 직접 링크를 무효로 설정한 사용자에게는 파일이 보이지 않거나, 썸네일이 생성되지 않기 때문에 통신량이 증가합니다. 일반적으로 이 설정을 ON으로 두는 것을 추천합니다."
local-drive-capacity-mb: "로컬 사용자 한 명당 드라이브 용량"
@ -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 {}"
@ -856,7 +855,6 @@ admin/views/index.vue:
moderators: "Moderatorzy"
users: "Użytkownicy"
announcements: "Ogłoszenia"
hashtags: "Hashtagi"
admin/views/dashboard.vue:
dashboard: "Kokpit"
accounts: "Konta"
@ -875,7 +873,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 +902,6 @@ admin/views/users.vue:
state:
all: "Wszyscy"
moderator: "Moderatorzy"
verified: "Zweryfikowane konto"
origin:
title: "Źródło"
local: "Lokalny"
@ -951,6 +947,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 +1187,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 +1195,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

@ -62,6 +62,7 @@ common:
month-and-day: "{month}月 {day}日"
trash: "垃圾箱"
drive: "网盘"
pages: "页面"
messaging: "聊天"
home: "首页"
deck: "Deck"
@ -144,7 +145,7 @@ common:
profile: "个人资料"
notification: "通知"
apps: "应用程序"
tags: "标签"
tags: "哈希标签"
mute-and-block: "屏蔽/拉黑"
blocking: "拉黑"
security: "安全性"
@ -167,7 +168,7 @@ common:
use-avatar-reversi-stones: "用头像作为黑白棋的棋子"
disable-animated-mfm: "在帖子中禁用动画文本"
disable-showing-animated-images: "不播放动画"
suggest-recent-hashtags: "在帖子表单上显示最近流行的主题标签"
suggest-recent-hashtags: "在帖子表单上显示最近流行的哈希标签"
always-show-nsfw: "总是显示 NSFW 的内容"
always-mark-nsfw: "总是用 NSFW 来标记附件"
show-full-acct: "不要从用户名中忽略主机名"
@ -250,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: "这是一个开发者测试版. 请勿在生产环境中使用."
@ -297,7 +297,7 @@ common:
server: "服务器信息"
nav: "导航"
tips: "提示"
hashtags: "标签"
hashtags: "哈希标签"
queue: "队列"
dev: "构建应用程序失败,请再试一次。"
ai-chan-kawaii: "小蓝真可爱"
@ -318,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: "新用户"
@ -469,9 +469,10 @@ common/views/components/nav.vue:
status: "状态"
wiki: "维基百科"
donors: "捐赠者"
repository: "码库"
repository: "码库"
develop: "开发人员"
feedback: "反馈"
tos: "服务条款"
common/views/components/note-menu.vue:
mention: "提到"
detail: "详细信息"
@ -584,6 +585,8 @@ common/views/components/signup.vue:
password-matched: "确认"
password-not-matched: "密码不一致"
recaptcha: "验证"
agree-to: "同意{0}"
tos: "服务条款"
create: "创建一个账户"
some-error: "由于某种原因,创建帐户失败。请再试一次。"
common/views/components/special-message.vue:
@ -713,7 +716,7 @@ common/views/widgets/posts-monitor.vue:
title: "投稿表格"
toggle: "切换视图"
common/views/widgets/hashtags.vue:
title: "标签"
title: "哈希标签"
common/views/widgets/server.vue:
title: "服务器信息"
toggle: "切换显示"
@ -1016,8 +1019,8 @@ desktop/views/components/timeline.vue:
mentions: "提到的"
messages: "直接发布"
list: "列表"
hashtag: "标签"
add-tag-timeline: "添加标签"
hashtag: "哈希标签"
add-tag-timeline: "添加哈希标签"
add-list: "添加列表"
list-name: "列表名称"
desktop/views/components/ui.header.vue:
@ -1063,7 +1066,6 @@ admin/views/index.vue:
users: "用户"
federation: "联合"
announcements: "公告"
hashtags: "标签"
abuse: "举报垃圾信息"
queue: "作业队列"
logs: "登录"
@ -1090,14 +1092,34 @@ admin/views/instance.vue:
instance-name: "实例名称"
instance-description: "实例介绍"
host: "主机名"
icon-url: "图标URL"
logo-url: "Logo URL"
banner-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: "每个用户的网盘空间"
@ -1108,6 +1130,9 @@ admin/views/instance.vue:
enable-recaptcha: "启用 reCAPTCHA\n(请注意, 此功能在中国大陆不可用. 如果启用, 可能导致无法正常使用登录或注册等功能)"
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"
@ -1138,7 +1163,8 @@ admin/views/instance.vue:
invite: "邀请"
save: "保存"
saved: "保存完毕"
user-recommendation-config: "推荐用户"
pinned-users: "置顶用户"
pinned-users-info: "描述您要置顶的用户,以换行符分隔。"
email-config: "电子邮件服务器设置"
email-config-info: "用于确认电子邮件和密码重置等。"
enable-email: "启用电子邮件送递"
@ -1222,14 +1248,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:
@ -1244,7 +1266,6 @@ admin/views/users.vue:
admin: "管理员"
moderator: "版主"
adminOrModerator: "管理员+版主"
verified: "官方认证账户"
silenced: "已禁言"
suspended: "已冻结"
origin:
@ -1306,6 +1327,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: "查询"
@ -1352,6 +1374,8 @@ admin/views/federation.vue:
chart-spans:
hour: "每小时"
day: "每天"
blocked-hosts: "拉黑"
blocked-hosts-info: "描述您要阻止的主机,以换行符分隔。"
desktop/views/pages/welcome.vue:
about: "更多信息..."
timeline: "时间线"
@ -1373,7 +1397,7 @@ desktop/views/pages/search.vue:
not-available: "在此实例的设置中关闭搜索功能。"
not-found: "没有找到“{q}”的帖子"
desktop/views/pages/tag.vue:
no-posts-found: "没有找到带有主题标签“{q}”的帖子"
no-posts-found: "没有找到带有哈希标签“{q}”的帖子"
desktop/views/pages/user-list.users.vue:
users: "用户"
add-user: "添加用户"
@ -1449,7 +1473,7 @@ mobile/views/components/drive.file-detail.vue:
download: "下载"
rename: "重命名"
move: "移动"
hash: "Hash (md5)"
hash: "哈希(md5)"
exif: "EXIF"
nsfw: "阅读注意"
mark-as-sensitive: "标记为“敏感”"
@ -1536,7 +1560,7 @@ mobile/views/pages/home.vue:
mentions: "Mentions"
messages: "直接发布"
mobile/views/pages/tag.vue:
no-posts-found: "没有找到带有主题标签“{q}”的帖子"
no-posts-found: "没有找到带有哈希标签“{q}”的帖子"
mobile/views/pages/widgets.vue:
dashboard: "仪表盘"
widgets-hints: "您可以添加/删除/重新排列小部件。 要移动小部件,请拖动“三”。 点击“×”删除小部件。 某些小部件可以通过点击来更改显示。"
@ -1588,7 +1612,7 @@ deck:
home: "首页"
local: "Local"
hybrid: "社交"
hashtag: "标签"
hashtag: "哈希标签"
global: "Global"
mentions: "Mentions"
direct: "直接发布"
@ -1622,25 +1646,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:
@ -1663,3 +1668,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,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

@ -0,0 +1,23 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class PageLike1558072954435 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`CREATE TABLE "page_like" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "pageId" character varying(32) NOT NULL, CONSTRAINT "PK_813f034843af992d3ae0f43c64c" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_0e61efab7f88dbb79c9166dbb4" ON "page_like" ("userId") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_4ce6fb9c70529b4c8ac46c9bfa" ON "page_like" ("userId", "pageId") `);
await queryRunner.query(`ALTER TABLE "page" ADD "likedCount" integer NOT NULL DEFAULT 0`);
await queryRunner.query(`ALTER TABLE "page_like" ADD CONSTRAINT "FK_0e61efab7f88dbb79c9166dbb48" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "page_like" ADD CONSTRAINT "FK_cf8782626dced3176038176a847" FOREIGN KEY ("pageId") REFERENCES "page"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "page_like" DROP CONSTRAINT "FK_cf8782626dced3176038176a847"`);
await queryRunner.query(`ALTER TABLE "page_like" DROP CONSTRAINT "FK_0e61efab7f88dbb79c9166dbb48"`);
await queryRunner.query(`ALTER TABLE "page" DROP COLUMN "likedCount"`);
await queryRunner.query(`DROP INDEX "IDX_4ce6fb9c70529b4c8ac46c9bfa"`);
await queryRunner.query(`DROP INDEX "IDX_0e61efab7f88dbb79c9166dbb4"`);
await queryRunner.query(`DROP TABLE "page_like"`);
}
}

View File

@ -0,0 +1,41 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class UserGroup1558103093633 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`CREATE TABLE "user_group" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "name" character varying(256) NOT NULL, "userId" character varying(32) NOT NULL, "isPrivate" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_3c29fba6fe013ec8724378ce7c9" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_20e30aa35180e317e133d75316" ON "user_group" ("createdAt") `);
await queryRunner.query(`CREATE INDEX "IDX_3d6b372788ab01be58853003c9" ON "user_group" ("userId") `);
await queryRunner.query(`CREATE TABLE "user_group_joining" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "userGroupId" character varying(32) NOT NULL, CONSTRAINT "PK_15f2425885253c5507e1599cfe7" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_f3a1b4bd0c7cabba958a0c0b23" ON "user_group_joining" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_67dc758bc0566985d1b3d39986" ON "user_group_joining" ("userGroupId") `);
await queryRunner.query(`ALTER TABLE "messaging_message" ADD "groupId" character varying(32)`);
await queryRunner.query(`ALTER TABLE "messaging_message" ADD "reads" character varying(32) array NOT NULL DEFAULT '{}'::varchar[]`);
await queryRunner.query(`ALTER TABLE "messaging_message" ALTER COLUMN "recipientId" DROP NOT NULL`);
await queryRunner.query(`COMMENT ON COLUMN "messaging_message"."recipientId" IS 'The recipient user ID.'`);
await queryRunner.query(`CREATE INDEX "IDX_2c4be03b446884f9e9c502135b" ON "messaging_message" ("groupId") `);
await queryRunner.query(`ALTER TABLE "messaging_message" ADD CONSTRAINT "FK_2c4be03b446884f9e9c502135be" FOREIGN KEY ("groupId") REFERENCES "user_group"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "user_group" ADD CONSTRAINT "FK_3d6b372788ab01be58853003c93" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "user_group_joining" ADD CONSTRAINT "FK_f3a1b4bd0c7cabba958a0c0b231" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "user_group_joining" ADD CONSTRAINT "FK_67dc758bc0566985d1b3d399865" FOREIGN KEY ("userGroupId") REFERENCES "user_group"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "user_group_joining" DROP CONSTRAINT "FK_67dc758bc0566985d1b3d399865"`);
await queryRunner.query(`ALTER TABLE "user_group_joining" DROP CONSTRAINT "FK_f3a1b4bd0c7cabba958a0c0b231"`);
await queryRunner.query(`ALTER TABLE "user_group" DROP CONSTRAINT "FK_3d6b372788ab01be58853003c93"`);
await queryRunner.query(`ALTER TABLE "messaging_message" DROP CONSTRAINT "FK_2c4be03b446884f9e9c502135be"`);
await queryRunner.query(`DROP INDEX "IDX_2c4be03b446884f9e9c502135b"`);
await queryRunner.query(`COMMENT ON COLUMN "messaging_message"."recipientId" IS ''`);
await queryRunner.query(`ALTER TABLE "messaging_message" ALTER COLUMN "recipientId" SET NOT NULL`);
await queryRunner.query(`ALTER TABLE "messaging_message" DROP COLUMN "reads"`);
await queryRunner.query(`ALTER TABLE "messaging_message" DROP COLUMN "groupId"`);
await queryRunner.query(`DROP INDEX "IDX_67dc758bc0566985d1b3d39986"`);
await queryRunner.query(`DROP INDEX "IDX_f3a1b4bd0c7cabba958a0c0b23"`);
await queryRunner.query(`DROP TABLE "user_group_joining"`);
await queryRunner.query(`DROP INDEX "IDX_3d6b372788ab01be58853003c9"`);
await queryRunner.query(`DROP INDEX "IDX_20e30aa35180e317e133d75316"`);
await queryRunner.query(`DROP TABLE "user_group"`);
}
}

View File

@ -0,0 +1,25 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class UserGroupInvite1558257926829 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`CREATE TABLE "user_group_invite" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "userGroupId" character varying(32) NOT NULL, CONSTRAINT "PK_3893884af0d3a5f4d01e7921a97" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_1039988afa3bf991185b277fe0" ON "user_group_invite" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_e10924607d058004304611a436" ON "user_group_invite" ("userGroupId") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_78787741f9010886796f2320a4" ON "user_group_invite" ("userId", "userGroupId") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_d9ecaed8c6dc43f3592c229282" ON "user_group_joining" ("userId", "userGroupId") `);
await queryRunner.query(`ALTER TABLE "user_group_invite" ADD CONSTRAINT "FK_1039988afa3bf991185b277fe03" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "user_group_invite" ADD CONSTRAINT "FK_e10924607d058004304611a436a" FOREIGN KEY ("userGroupId") REFERENCES "user_group"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`ALTER TABLE "user_group_invite" DROP CONSTRAINT "FK_e10924607d058004304611a436a"`);
await queryRunner.query(`ALTER TABLE "user_group_invite" DROP CONSTRAINT "FK_1039988afa3bf991185b277fe03"`);
await queryRunner.query(`DROP INDEX "IDX_d9ecaed8c6dc43f3592c229282"`);
await queryRunner.query(`DROP INDEX "IDX_78787741f9010886796f2320a4"`);
await queryRunner.query(`DROP INDEX "IDX_e10924607d058004304611a436"`);
await queryRunner.query(`DROP INDEX "IDX_1039988afa3bf991185b277fe0"`);
await queryRunner.query(`DROP TABLE "user_group_invite"`);
}
}

View File

@ -0,0 +1,13 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class UserListJoining1558266512381 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_90f7da835e4c10aca6853621e1" ON "user_list_joining" ("userId", "userListId") `);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`DROP INDEX "IDX_90f7da835e4c10aca6853621e1"`);
}
}

View File

@ -1,7 +1,7 @@
{
"name": "misskey",
"author": "syuilo <i@syuilo.com>",
"version": "11.11.0",
"version": "11.17.1",
"codename": "daybreak",
"repository": {
"type": "git",
@ -12,6 +12,9 @@
"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",
"migrateandstart": "npm run migrate && npm run start",
"build": "webpack && gulp build",
"webpack": "webpack",
"watch": "webpack --watch",
@ -94,13 +97,13 @@
"@types/websocket": "0.0.40",
"@types/ws": "6.0.1",
"animejs": "3.0.1",
"apexcharts": "3.6.9",
"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.8.1",
"bull": "3.9.1",
"cafy": "15.1.1",
"chai": "4.2.0",
"chalk": "2.4.2",
@ -121,7 +124,7 @@
"feed": "2.0.4",
"file-type": "10.11.0",
"fuckadblock": "3.2.1",
"gulp": "4.0.1",
"gulp": "4.0.2",
"gulp-cssnano": "2.1.3",
"gulp-imagemin": "5.0.3",
"gulp-mocha": "6.0.0",
@ -140,7 +143,7 @@
"is-root": "2.1.0",
"is-svg": "4.1.0",
"js-yaml": "3.13.1",
"jsdom": "15.0.0",
"jsdom": "15.1.0",
"json5": "2.1.0",
"json5-loader": "2.0.0",
"katex": "0.10.1",
@ -173,7 +176,7 @@
"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",
@ -247,11 +250,11 @@
"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.1",
"web-push": "3.3.4",
"webpack": "4.31.0",
"webpack-cli": "3.3.2",
"websocket": "1.0.28",
"ws": "7.0.0",
"xev": "2.0.1"

View File

@ -1,7 +1,7 @@
<template>
<div>
<ui-card>
<template #title><fa icon="broadcast-tower"/> {{ $t('announcements') }}</template>
<template #title><fa :icon="faBroadcastTower"/> {{ $t('announcements') }}</template>
<section v-for="(announcement, i) in announcements" class="fit-top">
<ui-input v-model="announcement.title" @change="save">
<span>{{ $t('title') }}</span>
@ -18,7 +18,7 @@
</ui-horizon-group>
</section>
<section>
<ui-button @click="add"><fa icon="plus"/> {{ $t('add') }}</ui-button>
<ui-button @click="add"><fa :icon="faPlus"/> {{ $t('add') }}</ui-button>
</section>
</ui-card>
</div>
@ -27,12 +27,14 @@
<script lang="ts">
import Vue from 'vue';
import i18n from '../../i18n';
import { faBroadcastTower, faPlus } from '@fortawesome/free-solid-svg-icons';
export default Vue.extend({
i18n: i18n('admin/views/announcements.vue'),
data() {
return {
announcements: [],
faBroadcastTower, faPlus
};
},

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,233 @@
<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 v-if="enableRecaptcha && recaptchaSiteKey">
<header>{{ $t('recaptcha-preview') }}</header>
<div ref="recaptcha" style="margin: 16px 0 0 0;" :key="recaptchaSiteKey"></div>
</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 +245,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 +257,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 +289,6 @@ export default Vue.extend({
discordClientId: null,
discordClientSecret: null,
proxyAccount: null,
inviteCode: null,
summalyProxy: null,
enableEmail: false,
email: null,
@ -190,7 +301,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 +321,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 +365,56 @@ 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;
});
},
mounted() {
const renderRecaptchaPreview = () => {
if (!(window as any).grecaptcha) return;
if (!this.$refs.recaptcha) return;
if (!this.recaptchaSiteKey) return;
(window as any).grecaptcha.render(this.$refs.recaptcha, {
sitekey: this.recaptchaSiteKey
});
};
window.onRecaotchaLoad = () => {
renderRecaptchaPreview();
};
const head = document.getElementsByTagName('head')[0];
const script = document.createElement('script');
script.setAttribute('src', 'https://www.google.com/recaptcha/api.js?onload=onRecaotchaLoad');
head.appendChild(script);
this.$watch('enableRecaptcha', () => {
renderRecaptchaPreview();
});
this.$watch('recaptchaSiteKey', () => {
renderRecaptchaPreview();
});
},
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 +427,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 +469,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

@ -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

@ -18,6 +18,7 @@
<fa icon="spinner" pulse v-if="type === 'waiting'"/>
</div>
<header v-if="title" v-html="title"></header>
<header v-if="title == null && user">{{ $t('@.enter-username') }}</header>
<div class="body" v-if="text" v-html="text"></div>
<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>

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

@ -44,6 +44,8 @@ import uiSwitch from './ui/switch.vue';
import uiRadio from './ui/radio.vue';
import uiSelect from './ui/select.vue';
import uiInfo from './ui/info.vue';
import uiMargin from './ui/margin.vue';
import uiHr from './ui/hr.vue';
import formButton from './ui/form/button.vue';
import formRadio from './ui/form/radio.vue';
@ -91,5 +93,7 @@ Vue.component('ui-switch', uiSwitch);
Vue.component('ui-radio', uiRadio);
Vue.component('ui-select', uiSelect);
Vue.component('ui-info', uiInfo);
Vue.component('ui-margin', uiMargin);
Vue.component('ui-hr', uiHr);
Vue.component('form-button', formButton);
Vue.component('form-radio', formRadio);

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

@ -33,7 +33,16 @@ import * as autosize from 'autosize';
export default Vue.extend({
i18n: i18n('common/views/components/messaging-room.form.vue'),
props: ['user'],
props: {
user: {
type: Object,
requird: false,
},
group: {
type: Object,
requird: false,
},
},
data() {
return {
text: null,
@ -43,7 +52,7 @@ export default Vue.extend({
},
computed: {
draftId(): string {
return this.user.id;
return this.user ? 'user:' + this.user.id : 'group:' + this.group.id;
},
canSend(): boolean {
return (this.text != null && this.text != '') || this.file != null;
@ -159,7 +168,8 @@ export default Vue.extend({
send() {
this.sending = true;
this.$root.api('messaging/messages/create', {
userId: this.user.id,
userId: this.user ? this.user.id : undefined,
groupId: this.group ? this.group.id : undefined,
text: this.text ? this.text : undefined,
fileId: this.file ? this.file.id : undefined
}).then(message => {

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>
@ -23,7 +23,12 @@
<div></div>
<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
<footer>
<span class="read" v-if="isMe && message.isRead">{{ $t('is-read') }}</span>
<template v-if="isGroup">
<span class="read" v-if="message.reads.length > 0">{{ $t('is-read') }} {{ message.reads.length }}</span>
</template>
<template v-else>
<span class="read" v-if="isMe && message.isRead">{{ $t('is-read') }}</span>
</template>
<mk-time :time="message.createdAt"/>
<template v-if="message.is_edited"><fa icon="pencil-alt"/></template>
</footer>
@ -42,6 +47,9 @@ export default Vue.extend({
props: {
message: {
required: true
},
isGroup: {
required: false
}
},
computed: {

View File

@ -4,14 +4,14 @@
@drop.prevent.stop="onDrop"
>
<div class="body">
<p class="init" v-if="init"><fa icon="spinner .spin"/>{{ $t('@.loading') }}</p>
<p class="empty" v-if="!init && messages.length == 0"><fa icon="info-circle"/>{{ $t('empty') }}</p>
<p class="init" v-if="init"><fa icon="spinner" pulse fixed-width/>{{ $t('@.loading') }}</p>
<p class="empty" v-if="!init && messages.length == 0"><fa icon="info-circle"/>{{ user ? $t('not-talked-user') : $t('not-talked-group') }}</p>
<p class="no-history" v-if="!init && messages.length > 0 && !existMoreMessages"><fa :icon="faFlag"/>{{ $t('no-history') }}</p>
<button class="more" :class="{ fetching: fetchingMoreMessages }" v-if="existMoreMessages" @click="fetchMoreMessages" :disabled="fetchingMoreMessages">
<template v-if="fetchingMoreMessages"><fa icon="spinner" pulse fixed-width/></template>{{ fetchingMoreMessages ? $t('@.loading') : $t('@.load-more') }}
</button>
<template v-for="(message, i) in _messages">
<x-message :message="message" :key="message.id"/>
<x-message :message="message" :key="message.id" :is-group="group != null"/>
<p class="date" v-if="i != messages.length - 1 && message._date != _messages[i + 1]._date">
<span>{{ _messages[i + 1]._datetext }}</span>
</p>
@ -23,7 +23,7 @@
<button @click="onIndicatorClick"><i><fa :icon="faArrowCircleDown"/></i>{{ $t('new-message') }}</button>
</div>
</transition>
<x-form :user="user" ref="form"/>
<x-form :user="user" :group="group" ref="form"/>
</footer>
</div>
</template>
@ -34,17 +34,30 @@ import i18n from '../../../i18n';
import XMessage from './messaging-room.message.vue';
import XForm from './messaging-room.form.vue';
import { url } from '../../../config';
import { faArrowCircleDown } from '@fortawesome/free-solid-svg-icons';
import { faFlag } from '@fortawesome/free-regular-svg-icons';
import { faArrowCircleDown, faFlag } from '@fortawesome/free-solid-svg-icons';
export default Vue.extend({
i18n: i18n('common/views/components/messaging-room.vue'),
components: {
XMessage,
XForm
},
props: ['user', 'isNaked'],
props: {
user: {
type: Object,
requird: false,
},
group: {
type: Object,
requird: false,
},
isNaked: {
type: Boolean,
requird: false,
},
},
data() {
return {
@ -76,7 +89,10 @@ export default Vue.extend({
},
mounted() {
this.connection = this.$root.stream.connectToChannel('messaging', { otherparty: this.user.id });
this.connection = this.$root.stream.connectToChannel('messaging', {
otherparty: this.user ? this.user.id : undefined,
group: this.group ? this.group.id : undefined,
});
this.connection.on('message', this.onMessage);
this.connection.on('read', this.onRead);
@ -147,7 +163,8 @@ export default Vue.extend({
const max = this.existMoreMessages ? 20 : 10;
this.$root.api('messaging/messages', {
userId: this.user.id,
userId: this.user ? this.user.id : undefined,
groupId: this.group ? this.group.id : undefined,
limit: max + 1,
untilId: this.existMoreMessages ? this.messages[0].id : undefined
}).then(messages => {
@ -199,12 +216,21 @@ export default Vue.extend({
}
},
onRead(ids) {
if (!Array.isArray(ids)) ids = [ids];
for (const id of ids) {
if (this.messages.some(x => x.id == id)) {
const exist = this.messages.map(x => x.id).indexOf(id);
this.messages[exist].isRead = true;
onRead(x) {
if (this.user) {
if (!Array.isArray(x)) x = [x];
for (const id of x) {
if (this.messages.some(x => x.id == id)) {
const exist = this.messages.map(x => x.id).indexOf(id);
this.messages[exist].isRead = true;
}
}
} else if (this.group) {
for (const id of x.ids) {
if (this.messages.some(x => x.id == id)) {
const exist = this.messages.map(x => x.id).indexOf(id);
this.messages[exist].reads.push(x.userId);
}
}
}
},

View File

@ -21,36 +21,62 @@
</div>
</div>
<div class="history" v-if="messages.length > 0">
<template>
<a v-for="message in messages"
class="user"
:href="`/i/messaging/${getAcct(isMe(message) ? message.recipient : message.user)}`"
:data-is-me="isMe(message)"
:data-is-read="message.isRead"
@click.prevent="navigate(isMe(message) ? message.recipient : message.user)"
:key="message.id"
>
<div>
<mk-avatar class="avatar" :user="isMe(message) ? message.recipient : message.user"/>
<header>
<span class="name"><mk-user-name :user="isMe(message) ? message.recipient : message.user"/></span>
<span class="username">@{{ isMe(message) ? message.recipient : message.user | acct }}</span>
<mk-time :time="message.createdAt"/>
</header>
<div class="body">
<p class="text"><span class="me" v-if="isMe(message)">{{ $t('you') }}:</span>{{ message.text }}</p>
</div>
<div class="title">{{ $t('user') }}</div>
<a v-for="message in messages"
class="user"
:href="`/i/messaging/${getAcct(isMe(message) ? message.recipient : message.user)}`"
:data-is-me="isMe(message)"
:data-is-read="message.isRead"
@click.prevent="navigate(isMe(message) ? message.recipient : message.user)"
:key="message.id"
>
<div>
<mk-avatar class="avatar" :user="isMe(message) ? message.recipient : message.user"/>
<header>
<span class="name"><mk-user-name :user="isMe(message) ? message.recipient : message.user"/></span>
<span class="username">@{{ isMe(message) ? message.recipient : message.user | acct }}</span>
<mk-time :time="message.createdAt"/>
</header>
<div class="body">
<p class="text"><span class="me" v-if="isMe(message)">{{ $t('you') }}:</span>{{ message.text }}</p>
</div>
</a>
</template>
</div>
</a>
</div>
<p class="no-history" v-if="!fetching && messages.length == 0">{{ $t('no-history') }}</p>
<div class="history" v-if="groupMessages.length > 0">
<div class="title">{{ $t('group') }}</div>
<a v-for="message in groupMessages"
class="user"
:href="`/i/messaging/group/${message.groupId}`"
:data-is-me="isMe(message)"
:data-is-read="message.reads.includes($store.state.i.id)"
@click.prevent="navigateGroup(message.group)"
:key="message.id"
>
<div>
<mk-avatar class="avatar" :user="message.user"/>
<header>
<span class="name">{{ message.group.name }}</span>
<mk-time :time="message.createdAt"/>
</header>
<div class="body">
<p class="text"><span class="me" v-if="isMe(message)">{{ $t('you') }}:</span>{{ message.text }}</p>
</div>
</div>
</a>
</div>
<p class="no-history" v-if="!fetching && (messages.length == 0 && groupMessages.length == 0)">{{ $t('no-history') }}</p>
<p class="fetching" v-if="fetching"><fa icon="spinner" pulse fixed-width/>{{ $t('@.loading') }}<mk-ellipsis/></p>
<ui-margin>
<ui-button @click="startUser()"><fa :icon="faUser"/> {{ $t('start-with-user') }}</ui-button>
<ui-button @click="startGroup()"><fa :icon="faUsers"/> {{ $t('start-with-group') }}</ui-button>
</ui-margin>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import { faUser, faUsers } from '@fortawesome/free-solid-svg-icons';
import i18n from '../../../i18n';
import getAcct from '../../../../../misc/acct/render';
@ -71,9 +97,11 @@ export default Vue.extend({
fetching: true,
moreFetching: false,
messages: [],
groupMessages: [],
q: null,
result: [],
connection: null
connection: null,
faUser, faUsers
};
},
mounted() {
@ -82,9 +110,12 @@ export default Vue.extend({
this.connection.on('message', this.onMessage);
this.connection.on('read', this.onRead);
this.$root.api('messaging/history').then(messages => {
this.messages = messages;
this.fetching = false;
this.$root.api('messaging/history', { group: false }).then(messages => {
this.$root.api('messaging/history', { group: true }).then(groupMessages => {
this.messages = messages;
this.groupMessages = groupMessages;
this.fetching = false;
});
});
},
beforeDestroy() {
@ -96,16 +127,27 @@ export default Vue.extend({
return message.userId == this.$store.state.i.id;
},
onMessage(message) {
this.messages = this.messages.filter(m => !(
(m.recipientId == message.recipientId && m.userId == message.userId) ||
(m.recipientId == message.userId && m.userId == message.recipientId)));
if (message.recipientId) {
this.messages = this.messages.filter(m => !(
(m.recipientId == message.recipientId && m.userId == message.userId) ||
(m.recipientId == message.userId && m.userId == message.recipientId)));
this.messages.unshift(message);
this.messages.unshift(message);
} else if (message.groupId) {
this.groupMessages = this.groupMessages.filter(m => m.groupId !== message.groupId);
this.groupMessages.unshift(message);
}
},
onRead(ids) {
for (const id of ids) {
const found = this.messages.find(m => m.id == id);
if (found) found.isRead = true;
if (found) {
if (found.recipientId) {
found.isRead = true;
} else if (found.groupId) {
found.reads.push(this.$store.state.i.id);
}
}
}
},
search() {
@ -125,6 +167,9 @@ export default Vue.extend({
navigate(user) {
this.$emit('navigate', user);
},
navigateGroup(group) {
this.$emit('navigateGroup', group);
},
onSearchKeydown(e) {
switch (e.which) {
case 9: // [TAB]
@ -161,6 +206,31 @@ export default Vue.extend({
(list.childNodes[i].nextElementSibling || list.childNodes[0]).focus();
break;
}
},
async startUser() {
const { result: user } = await this.$root.dialog({
user: {
local: true
}
});
if (user == null) return;
this.navigate(user);
},
async startGroup() {
const groups1 = await this.$root.api('users/groups/owned');
const groups2 = await this.$root.api('users/groups/joined');
const { canceled, result: group } = await this.$root.dialog({
type: null,
title: this.$t('select-group'),
select: {
items: groups1.concat(groups2).map(group => ({
value: group, text: group.name
}))
},
showCancelButton: true
});
if (canceled) return;
this.navigateGroup(group);
}
}
});
@ -173,6 +243,9 @@ export default Vue.extend({
font-size 0.8em
> .history
> .title
padding 8px
> a
&:last-child
border-bottom none
@ -311,6 +384,13 @@ export default Vue.extend({
color rgba(#000, 0.3)
> .history
> .title
padding 6px 16px
margin 0 auto
max-width 500px
background rgba(0, 0, 0, 0.05)
color var(--text)
font-size 85%
> a
display block

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

@ -1,5 +1,5 @@
<template>
<x-container :removable="removable" @remove="() => $emit('remove')" :error="error" :warn="warn">
<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()">
@ -93,6 +93,10 @@ export default Vue.extend({
fnSlots: {
required: false,
},
draggable: {
required: false,
default: false
}
},
data() {

View File

@ -53,20 +53,19 @@
<ui-container :body-togglable="true">
<template #header><fa :icon="faMagic"/> {{ $t('variables') }}</template>
<div class="qmuvgica">
<div class="variables" v-show="variables.length > 0">
<template v-for="variable in variables">
<x-variable
:value="variable"
:removable="true"
@input="v => updateVariable(v)"
@remove="() => removeVariable(variable)"
:key="variable.name"
:ai-script="aiScript"
:name="variable.name"
:title="variable.name"
/>
</template>
</div>
<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>
@ -92,6 +91,7 @@
<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';
@ -107,7 +107,7 @@ export default Vue.extend({
i18n: i18n('pages'),
components: {
XVariable, XBlocks
XDraggable, XVariable, XBlocks
},
props: {

View File

@ -1,5 +1,5 @@
<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 }">
<router-link :to="`/@${page.user.username}/pages/${page.name}`" class="vhpxefrj" tabindex="-1">
<div class="thumbnail" v-if="page.eyeCatchingImage" :style="`background-image: url('${page.eyeCatchingImage.thumbnailUrl}')`"></div>
<article>
<header>
@ -32,16 +32,13 @@ export default Vue.extend({
display block
overflow hidden
width 100%
background var(--face)
border solid var(--lineWidth) var(--urlPreviewBorder)
border-radius 4px
overflow hidden
&.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)
&:hover
text-decoration none
border-color var(--urlPreviewBorderHover)
> .thumbnail
position absolute

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

@ -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>

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>

View File

@ -10,7 +10,7 @@
<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>

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

@ -113,7 +113,7 @@ export default Vue.extend({
padding 8px 10px
text-align center
font-weight normal
font-size 16px
font-size 14px
line-height 24px
border none
outline none

View File

@ -0,0 +1,15 @@
<template>
<div class="evrzpitu"></div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({});
</script>
<style lang="stylus" scoped>
.evrzpitu
margin 16px 0
border-bottom solid var(--lineWidth) var(--faceDivider)
</style>

View File

@ -0,0 +1,16 @@
<template>
<div class="zdcrxcne">
<slot></slot>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({});
</script>
<style lang="stylus" scoped>
.zdcrxcne
margin 16px
</style>

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

@ -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

@ -1,95 +0,0 @@
<template>
<div class="xkxvokkjlptzyewouewmceqcxhpgzprp">
<button class="ui" @click="add">{{ $t('create-list') }}</button>
<a v-for="list in lists" :key="list.id" @click="choice(list)">{{ list.name }}</a>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({
i18n: i18n('common/views/components/user-lists.vue'),
data() {
return {
fetching: true,
lists: []
};
},
mounted() {
this.$root.api('users/lists/list').then(lists => {
this.fetching = false;
this.lists = lists;
});
},
methods: {
add() {
this.$root.dialog({
title: this.$t('list-name'),
input: true
}).then(async ({ canceled, result: name }) => {
if (canceled) return;
const list = await this.$root.api('users/lists/create', {
name
});
this.lists.push(list)
this.$emit('choosen', list);
});
},
choice(list) {
this.$emit('choosen', list);
}
}
});
</script>
<style lang="stylus" scoped>
.xkxvokkjlptzyewouewmceqcxhpgzprp
padding 16px
background: var(--bg)
> button
display block
margin-bottom 16px
color var(--primaryForeground)
background var(--primary)
width 100%
border-radius 38px
user-select none
cursor pointer
padding 0 16px
min-width 100px
line-height 38px
font-size 14px
font-weight 700
&:hover
background var(--primaryLighten10)
&:active
background var(--primaryDarken10)
a
display block
margin 8px 0
padding 8px
color var(--text)
background var(--face)
box-shadow 0 2px 16px var(--reversiListItemShadow)
border-radius 6px
cursor pointer
line-height 32px
*
pointer-events none
user-select none
&:hover
box-shadow 0 0 0 100px inset rgba(0, 0, 0, 0.05)
&:active
box-shadow 0 0 0 100px inset rgba(0, 0, 0, 0.1)
</style>

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

@ -0,0 +1,45 @@
<template>
<x-column>
<template #header>
<fa v-if="icon" :icon="icon"/>{{ title }}
</template>
<div>
<component :is="component" @init="init" v-bind="$attrs"/>
</div>
</x-column>
</template>
<script lang="ts">
import Vue from 'vue';
import XColumn from './deck.column.vue';
export default Vue.extend({
components: {
XColumn,
},
props: {
component: {
required: true
}
},
data() {
return {
title: null,
icon: null,
};
},
mounted() {
},
methods: {
init(v) {
this.title = v.title;
this.icon = v.icon;
}
}
});
</script>

View File

@ -1,34 +0,0 @@
<template>
<x-column>
<template #header>
<fa :icon="faHashtag"/>{{ $t('@.explore') }}
</template>
<div>
<x-explore v-bind="$attrs"/>
</div>
</x-column>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
import XColumn from './deck.column.vue';
import XExplore from '../../../common/views/pages/explore.vue';
import { faHashtag } from '@fortawesome/free-solid-svg-icons';
export default Vue.extend({
i18n: i18n(),
components: {
XColumn,
XExplore,
},
data() {
return {
faHashtag
};
}
});
</script>

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

@ -8,7 +8,7 @@
<div class="is-remote" v-if="user.host != null">
<details>
<summary><fa icon="exclamation-triangle"/> {{ $t('@.is-remote-user') }}</summary>
<a :href="user.url" target="_blank">{{ $t('@.view-on-remote') }}</a>
<a :href="user.url" rel="nofollow noopener" target="_blank">{{ $t('@.view-on-remote') }}</a>
</details>
</div>
<header :style="bannerStyle">

View File

@ -13,8 +13,8 @@
<template #header><fa :icon="faHashtag" fixed-width/>{{ $t('popular-tags') }}</template>
<div class="vxjfqztj">
<router-link v-for="tag in tagsLocal" :to="`/explore/tags/${tag.name}`" :key="'local:' + tag.name" class="local">{{ tag.name }}</router-link>
<router-link v-for="tag in tagsRemote" :to="`/explore/tags/${tag.name}`" :key="'remote:' + tag.name">{{ tag.name }}</router-link>
<router-link v-for="tag in tagsLocal" :to="`/explore/tags/${tag.tag}`" :key="'local:' + tag.tag" class="local">{{ tag.tag }}</router-link>
<router-link v-for="tag in tagsRemote" :to="`/explore/tags/${tag.tag}`" :key="'remote:' + tag.tag">{{ tag.tag }}</router-link>
</div>
</ui-container>
@ -26,8 +26,8 @@
</mk-user-list>
<template v-if="tag == null">
<mk-user-list :make-promise="verifiedUsers">
<fa :icon="faBookmark" fixed-width/>{{ $t('verified-users') }}
<mk-user-list :make-promise="pinnedUsers">
<fa :icon="faBookmark" fixed-width/>{{ $t('pinned-users') }}
</mk-user-list>
<mk-user-list :make-promise="popularUsers">
<fa :icon="faChartLine" fixed-width/>{{ $t('popular-users') }}
@ -60,12 +60,7 @@ export default Vue.extend({
data() {
return {
verifiedUsers: () => this.$root.api('users', {
state: 'verified',
origin: 'local',
sort: '+follower',
limit: 10
}),
pinnedUsers: () => this.$root.api('pinned-users'),
popularUsers: () => this.$root.api('users', {
state: 'alive',
origin: 'local',
@ -121,6 +116,10 @@ export default Vue.extend({
},
created() {
this.$emit('init', {
title: this.$t('@.explore'),
icon: faHashtag
});
this.$root.api('hashtags/list', {
sort: '+attachedLocalUsers',
attachedToLocalUserOnly: true,

View File

@ -1,27 +1,30 @@
<template>
<mk-ui>
<template #header><fa :icon="['far', 'envelope']"/>{{ $t('title') }}</template>
<main>
<div v-for="req in requests">
<router-link :key="req.id" :to="req.follower | userPage">
<mk-user-name :user="req.follower"/>
</router-link>
<span>
<a @click="accept(req.follower)">{{ $t('accept') }}</a>|<a @click="reject(req.follower)">{{ $t('reject') }}</a>
</span>
<div>
<ui-container :body-togglable="true">
<template #header>{{ $t('received-follow-requests') }}</template>
<div v-if="!fetching">
<sequential-entrance animation="entranceFromTop" delay="25" tag="div">
<div v-for="req in requests" class="mcbzkkaw">
<router-link :key="req.id" :to="req.follower | userPage">
<mk-user-name :user="req.follower"/>
</router-link>
<span>
<a @click="accept(req.follower)">{{ $t('accept') }}</a>|<a @click="reject(req.follower)">{{ $t('reject') }}</a>
</span>
</div>
</sequential-entrance>
</div>
</main>
</mk-ui>
</ui-container>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
import Progress from '../../../common/scripts/loading';
import Progress from '../../scripts/loading';
export default Vue.extend({
i18n: i18n('mobile/views/pages/received-follow-requests.vue'),
i18n: i18n('common/views/pages/follow-requests.vue'),
data() {
return {
fetching: true,
@ -29,14 +32,10 @@ export default Vue.extend({
};
},
mounted() {
document.title = this.$t('title');
Progress.start();
this.$root.api('following/requests/list').then(requests => {
this.fetching = false;
this.requests = requests;
Progress.done();
});
},
@ -56,14 +55,13 @@ export default Vue.extend({
</script>
<style lang="stylus" scoped>
main
> div
display flex
padding 16px
border solid 1px var(--faceDivider)
border-radius 4px
.mcbzkkaw
display flex
padding 16px
border solid 1px var(--faceDivider)
border-radius 4px
> span
margin 0 0 0 auto
> span
margin 0 0 0 auto
</style>

View File

@ -12,6 +12,11 @@
<small>@{{ page.user.username }}</small>
<router-link v-if="$store.getters.isSignedIn && $store.state.i.id === page.userId" :to="`/i/pages/edit/${page.id}`">{{ $t('edit-this-page') }}</router-link>
<router-link :to="`./${page.name}/view-source`">{{ $t('view-source') }}</router-link>
<div class="like">
<button @click="unlike()" v-if="page.isLiked" :title="$t('unlike')"><fa :icon="faHeartS"/></button>
<button @click="like()" v-else :title="$t('like')"><fa :icon="faHeart"/></button>
<span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span>
</div>
</footer>
</div>
</template>
@ -19,8 +24,8 @@
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../../i18n';
import { faICursor, faPlus } from '@fortawesome/free-solid-svg-icons';
import { faSave, faStickyNote } from '@fortawesome/free-regular-svg-icons';
import { faHeart as faHeartS } from '@fortawesome/free-solid-svg-icons';
import { faHeart } from '@fortawesome/free-regular-svg-icons';
import XBlock from './page.block.vue';
import { ASEvaluator } from '../../../../../../misc/aiscript/evaluator';
import { collectPageVars } from '../../../scripts/collect-page-vars';
@ -76,7 +81,7 @@ export default Vue.extend({
return {
page: null,
script: null,
faPlus, faICursor, faSave, faStickyNote
faHeartS, faHeart
};
},
@ -103,6 +108,24 @@ export default Vue.extend({
getPageVars() {
return collectPageVars(this.page.content);
},
like() {
this.$root.api('pages/like', {
pageId: this.page.id,
}).then(() => {
this.page.isLiked = true;
this.page.likedCount++;
});
},
unlike() {
this.$root.api('pages/unlike', {
pageId: this.page.id,
}).then(() => {
this.page.isLiked = false;
this.page.likedCount--;
});
}
}
});
</script>
@ -161,4 +184,7 @@ export default Vue.extend({
> a + a
margin-left 8px
> .like
margin-top 16px
</style>

View File

@ -0,0 +1,143 @@
<template>
<div>
<ui-container :body-togglable="true">
<template #header><fa :icon="faEdit" fixed-width/>{{ $t('my-pages') }}</template>
<div class="rknalgpo" v-if="!fetching">
<ui-button class="new" @click="create()"><fa :icon="faPlus"/></ui-button>
<sequential-entrance animation="entranceFromTop" delay="25" tag="div" class="pages">
<x-page-preview v-for="page in pages" class="page" :page="page" :key="page.id"/>
</sequential-entrance>
<ui-button v-if="existMore" @click="fetchMore()" style="margin-top:16px;">{{ $t('@.load-more') }}</ui-button>
</div>
</ui-container>
<ui-container :body-togglable="true">
<template #header><fa :icon="faHeart" fixed-width/>{{ $t('liked-pages') }}</template>
<div class="rknalgpo" v-if="!fetching">
<sequential-entrance animation="entranceFromTop" delay="25" tag="div" class="pages">
<x-page-preview v-for="like in likes" class="page" :page="like.page" :key="like.page.id"/>
</sequential-entrance>
<ui-button v-if="existMoreLikes" @click="fetchMoreLiked()">{{ $t('@.load-more') }}</ui-button>
</div>
</ui-container>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import { faPlus, faEdit } from '@fortawesome/free-solid-svg-icons';
import { faStickyNote, faHeart } from '@fortawesome/free-regular-svg-icons';
import i18n from '../../../i18n';
import Progress from '../../scripts/loading';
import XPagePreview from '../../views/components/page-preview.vue';
export default Vue.extend({
i18n: i18n('pages'),
components: {
XPagePreview
},
data() {
return {
fetching: true,
pages: [],
existMore: false,
moreFetching: false,
likes: [],
existMoreLikes: false,
moreLikesFetching: false,
faStickyNote, faPlus, faEdit, faHeart
};
},
created() {
this.fetch();
this.$emit('init', {
title: this.$t('@.pages'),
icon: faStickyNote
});
},
methods: {
async fetch() {
Progress.start();
this.fetching = true;
const pages = await this.$root.api('i/pages', {
limit: 11
});
if (pages.length == 11) {
this.existMore = true;
pages.pop();
}
const likes = await this.$root.api('i/page-likes', {
limit: 11
});
if (likes.length == 11) {
this.existMoreLikes = true;
likes.pop();
}
this.pages = pages;
this.likes = likes;
this.fetching = false;
Progress.done();
},
fetchMore() {
this.moreFetching = true;
this.$root.api('i/pages', {
limit: 11,
untilId: this.pages[this.pages.length - 1].id
}).then(pages => {
if (pages.length == 11) {
this.existMore = true;
pages.pop();
} else {
this.existMore = false;
}
this.pages = this.pages.concat(pages);
this.moreFetching = false;
});
},
fetchMoreLiked() {
this.moreLikesFetching = true;
this.$root.api('i/page-likes', {
limit: 11,
untilId: this.likes[this.likes.length - 1].id
}).then(pages => {
if (pages.length == 11) {
this.existMoreLikes = true;
pages.pop();
} else {
this.existMoreLikes = false;
}
this.likes = this.likes.concat(pages);
this.moreLikesFetching = false;
});
},
create() {
this.$router.push(`/i/pages/new`);
}
}
});
</script>
<style lang="stylus" scoped>
.rknalgpo
padding 16px
> .new
margin-bottom 16px
> * > .page:not(:last-child)
margin-bottom 8px
@media (min-width 500px)
> * > .page:not(:last-child)
margin-bottom 16px
</style>

View File

@ -0,0 +1,186 @@
<template>
<div class="ivrbakop">
<ui-container v-if="group">
<template #header><fa :icon="faUsers"/> {{ group.name }}</template>
<section>
<ui-margin>
<ui-button @click="rename"><fa :icon="faICursor"/> {{ $t('rename') }}</ui-button>
<ui-button @click="del"><fa :icon="faTrashAlt"/> {{ $t('delete') }}</ui-button>
</ui-margin>
</section>
</ui-container>
<ui-container>
<template #header><fa :icon="faUsers"/> {{ $t('users') }}</template>
<section>
<ui-margin>
<ui-button @click="invite()"><fa :icon="faPlus"/> {{ $t('invite') }}</ui-button>
</ui-margin>
<sequential-entrance animation="entranceFromTop" delay="25">
<div class="kjlrfbes" v-for="user in users">
<div>
<a :href="user | userPage">
<mk-avatar class="avatar" :user="user" :disable-link="true"/>
</a>
</div>
<div>
<header>
<b><mk-user-name :user="user"/></b>
<span class="username">@{{ user | acct }}</span>
</header>
<div>
<a @click="remove(user)">{{ $t('remove-user') }}</a>
</div>
</div>
</div>
</sequential-entrance>
</section>
</ui-container>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
import { faICursor, faUsers, faPlus } from '@fortawesome/free-solid-svg-icons';
import { faTrashAlt } from '@fortawesome/free-regular-svg-icons';
export default Vue.extend({
i18n: i18n('common/views/components/user-group-editor.vue'),
props: {
groupId: {
required: true
}
},
data() {
return {
group: null,
users: [],
faICursor, faTrashAlt, faUsers, faPlus
};
},
created() {
this.$root.api('users/groups/show', {
groupId: this.groupId
}).then(group => {
this.group = group;
this.fetchUsers();
this.$emit('init', {
title: this.group.name,
icon: faUsers
});
});
},
methods: {
fetchUsers() {
this.$root.api('users/show', {
userIds: this.group.userIds
}).then(users => {
this.users = users;
});
},
rename() {
this.$root.dialog({
title: this.$t('rename'),
input: {
default: this.group.name
}
}).then(({ canceled, result: name }) => {
if (canceled) return;
this.$root.api('users/groups/update', {
groupId: this.group.id,
name: name
});
});
},
del() {
this.$root.dialog({
type: 'warning',
text: this.$t('delete-are-you-sure').replace('$1', this.group.name),
showCancelButton: true
}).then(({ canceled }) => {
if (canceled) return;
this.$root.api('users/groups/delete', {
groupId: this.group.id
}).then(() => {
this.$root.dialog({
type: 'success',
text: this.$t('deleted')
});
}).catch(e => {
this.$root.dialog({
type: 'error',
text: e
});
});
});
},
remove(user: any) {
this.$root.api('users/groups/pull', {
groupId: this.group.id,
userId: user.id
}).then(() => {
this.fetchUsers();
});
},
async invite() {
const t = this.$t('invited');
const { result: user } = await this.$root.dialog({
user: {
local: true
}
});
if (user == null) return;
this.$root.api('users/groups/invite', {
groupId: this.group.id,
userId: user.id
}).then(() => {
this.$root.dialog({
type: 'success',
text: t
});
});
}
}
});
</script>
<style lang="stylus" scoped>
.ivrbakop
.kjlrfbes
display flex
padding 16px
border-top solid 1px var(--faceDivider)
> div:first-child
> a
> .avatar
width 64px
height 64px
> div:last-child
flex 1
padding-left 16px
@media (max-width 500px)
font-size 14px
> header
color var(--text)
> .username
margin-left 8px
opacity 0.7
</style>

View File

@ -0,0 +1,119 @@
<template>
<div>
<ui-container>
<template #header><fa :icon="faUsers"/> {{ $t('owned-groups') }}</template>
<ui-margin>
<ui-button @click="add"><fa :icon="faPlus"/> {{ $t('create-group') }}</ui-button>
</ui-margin>
<div class="hwgkdrbl" v-for="group in ownedGroups" :key="group.id">
<ui-hr/>
<ui-margin>
<router-link :to="`/i/groups/${group.id}`">{{ group.name }}</router-link>
</ui-margin>
</div>
</ui-container>
<ui-container>
<template #header><fa :icon="faUsers"/> {{ $t('joined-groups') }}</template>
<div class="hwgkdrbl" v-for="(group, i) in joinedGroups" :key="group.id">
<ui-hr v-if="i != 0"/>
<ui-margin>
<router-link :to="`/i/groups/${group.id}`">{{ group.name }}</router-link>
</ui-margin>
</div>
</ui-container>
<ui-container>
<template #header><fa :icon="faEnvelopeOpenText"/> {{ $t('invites') }}</template>
<div class="fvlojuur" v-for="(invite, i) in invites" :key="invite.id">
<ui-hr v-if="i != 0"/>
<ui-margin>
<div class="name">{{ invite.group.name }}</div>
<ui-horizon-group>
<ui-button @click="acceptInvite(invite)"><fa :icon="faCheck"/> {{ $t('accept-invite') }}</ui-button>
<ui-button @click="rejectInvite(invite)"><fa :icon="faBan"/> {{ $t('reject-invite') }}</ui-button>
</ui-horizon-group>
</ui-margin>
</div>
</ui-container>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
import { faUsers, faPlus, faCheck, faBan, faEnvelopeOpenText } from '@fortawesome/free-solid-svg-icons';
export default Vue.extend({
i18n: i18n('common/views/components/user-groups.vue'),
data() {
return {
ownedGroups: [],
joinedGroups: [],
invites: [],
faUsers, faPlus, faCheck, faBan, faEnvelopeOpenText
};
},
mounted() {
this.$root.api('users/groups/owned').then(groups => {
this.ownedGroups = groups;
});
this.$root.api('users/groups/joined').then(groups => {
this.joinedGroups = groups;
});
this.$root.api('i/user-group-invites').then(invites => {
this.invites = invites;
});
this.$emit('init', {
title: this.$t('user-groups'),
icon: faUsers
});
},
methods: {
add() {
this.$root.dialog({
title: this.$t('group-name'),
input: true
}).then(async ({ canceled, result: name }) => {
if (canceled) return;
const group = await this.$root.api('users/groups/create', {
name
});
this.ownedGroups.push(group)
});
},
acceptInvite(invite) {
this.$root.api('users/groups/invitations/accept', {
inviteId: invite.id
}).then(() => {
this.$root.dialog({
type: 'success',
splash: true
});
this.$root.api('i/user-group-invites').then(invites => {
this.invites = invites;
});
});
},
rejectInvite(invite) {
this.$root.api('users/groups/invitations/reject', {
inviteId: invite.id
}).then(() => {
this.$root.api('i/user-group-invites').then(invites => {
this.invites = invites;
});
});
}
}
});
</script>
<style lang="stylus" scoped>
.hwgkdrbl
display block
</style>

View File

@ -1,18 +1,23 @@
<template>
<div class="cudqjmnl">
<ui-card>
<template #title><fa :icon="faList"/> {{ list.name }}</template>
<ui-container v-if="list">
<template #header><fa :icon="faListUl"/> {{ list.name }}</template>
<section>
<ui-button @click="rename"><fa :icon="faICursor"/> {{ $t('rename') }}</ui-button>
<ui-button @click="del"><fa :icon="faTrashAlt"/> {{ $t('delete') }}</ui-button>
<section class="fwvevrks">
<ui-margin>
<ui-button @click="rename"><fa :icon="faICursor"/> {{ $t('rename') }}</ui-button>
<ui-button @click="del"><fa :icon="faTrashAlt"/> {{ $t('delete') }}</ui-button>
</ui-margin>
</section>
</ui-card>
</ui-container>
<ui-card>
<template #title><fa :icon="faUsers"/> {{ $t('users') }}</template>
<ui-container>
<template #header><fa :icon="faUsers"/> {{ $t('users') }}</template>
<section>
<ui-margin>
<ui-button @click="add"><fa :icon="faPlus"/> {{ $t('add-user') }}</ui-button>
</ui-margin>
<sequential-entrance animation="entranceFromTop" delay="25">
<div class="phcqulfl" v-for="user in users">
<div>
@ -32,34 +37,44 @@
</div>
</sequential-entrance>
</section>
</ui-card>
</ui-container>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
import { faList, faICursor, faUsers } from '@fortawesome/free-solid-svg-icons';
import { faListUl, faICursor, faUsers, faPlus } from '@fortawesome/free-solid-svg-icons';
import { faTrashAlt } from '@fortawesome/free-regular-svg-icons';
export default Vue.extend({
i18n: i18n('common/views/components/user-list-editor.vue'),
props: {
list: {
listId: {
required: true
}
},
data() {
return {
list: null,
users: [],
faList, faICursor, faTrashAlt, faUsers
faListUl, faICursor, faTrashAlt, faUsers, faPlus
};
},
mounted() {
this.fetchUsers();
created() {
this.$root.api('users/lists/show', {
listId: this.listId
}).then(list => {
this.list = list;
this.fetchUsers();
this.$emit('init', {
title: this.list.name,
icon: faListUl
});
});
},
methods: {
@ -117,6 +132,21 @@ export default Vue.extend({
}).then(() => {
this.fetchUsers();
});
},
async add() {
const { result: user } = await this.$root.dialog({
user: {
local: true
}
});
if (user == null) return;
this.$root.api('users/lists/push', {
listId: this.list.id,
userId: user.id
}).then(() => {
this.fetchUsers();
});
}
}
});
@ -126,7 +156,7 @@ export default Vue.extend({
.cudqjmnl
.phcqulfl
display flex
padding 16px 0
padding 16px
border-top solid 1px var(--faceDivider)
> div:first-child
@ -143,6 +173,8 @@ export default Vue.extend({
font-size 14px
> header
color var(--text)
> .username
margin-left 8px
opacity 0.7

View File

@ -0,0 +1,63 @@
<template>
<ui-container>
<template #header><fa :icon="faListUl"/> {{ $t('user-lists') }}</template>
<ui-margin>
<ui-button @click="add"><fa :icon="faPlus"/> {{ $t('create-list') }}</ui-button>
</ui-margin>
<div class="cpqqyrst" v-for="list in lists" :key="list.id">
<ui-hr/>
<ui-margin>
<router-link :to="`/i/lists/${list.id}`">{{ list.name }}</router-link>
</ui-margin>
</div>
</ui-container>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
import { faListUl, faPlus } from '@fortawesome/free-solid-svg-icons';
export default Vue.extend({
i18n: i18n('common/views/components/user-lists.vue'),
data() {
return {
fetching: true,
lists: [],
faListUl, faPlus
};
},
mounted() {
this.$root.api('users/lists/list').then(lists => {
this.fetching = false;
this.lists = lists;
});
this.$emit('init', {
title: this.$t('user-lists'),
icon: faListUl
});
},
methods: {
add() {
this.$root.dialog({
title: this.$t('list-name'),
input: true
}).then(async ({ canceled, result: name }) => {
if (canceled) return;
const list = await this.$root.api('users/lists/create', {
name
});
this.lists.push(list)
});
},
}
});
</script>
<style lang="stylus" scoped>
.cpqqyrst
display block
</style>

View File

@ -7,7 +7,7 @@
<div class="mkw-rss--body" :data-mobile="platform == 'mobile'">
<p class="fetching" v-if="fetching"><fa icon="spinner" pulse fixed-width/>{{ $t('@.loading') }}<mk-ellipsis/></p>
<div class="feed" v-else>
<a v-for="item in items" :href="item.link" target="_blank" :title="item.title">{{ item.title }}</a>
<a v-for="item in items" :href="item.link" rel="nofollow noopener" target="_blank" :title="item.title">{{ item.title }}</a>
</div>
</div>
</ui-container>

View File

@ -22,6 +22,7 @@ import MkShare from '../common/views/pages/share.vue';
import MkFollow from '../common/views/pages/follow.vue';
import MkNotFound from '../common/views/pages/not-found.vue';
import MkSettings from './views/pages/settings.vue';
import DeckColumn from '../common/views/deck/deck.column-template.vue';
import Ctx from './views/components/context-menu.vue';
import PostFormWindow from './views/components/post-form-window.vue';
@ -138,9 +139,14 @@ init(async (launch, os) => {
{ path: '/search', component: () => import('../common/views/deck/deck.search-column.vue').then(m => m.default) },
{ path: '/tags/:tag', name: 'tag', component: () => import('../common/views/deck/deck.hashtag-column.vue').then(m => m.default) },
{ path: '/featured', name: 'featured', component: () => import('../common/views/deck/deck.featured-column.vue').then(m => m.default) },
{ path: '/explore', name: 'explore', component: () => import('../common/views/deck/deck.explore-column.vue').then(m => m.default) },
{ path: '/explore/tags/:tag', name: 'explore-tag', props: true, component: () => import('../common/views/deck/deck.explore-column.vue').then(m => m.default) },
{ path: '/i/favorites', component: () => import('../common/views/deck/deck.favorites-column.vue').then(m => m.default) }
{ path: '/explore', name: 'explore', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/explore.vue').then(m => m.default) }) },
{ path: '/explore/tags/:tag', name: 'explore-tag', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/explore.vue').then(m => m.default), tag: route.params.tag }) },
{ path: '/i/favorites', component: () => import('../common/views/deck/deck.favorites-column.vue').then(m => m.default) },
{ path: '/i/pages', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/pages.vue').then(m => m.default) }) },
{ path: '/i/lists', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/user-lists.vue').then(m => m.default) }) },
{ path: '/i/lists/:listId', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/user-list-editor.vue').then(m => m.default), listId: route.params.listId }) },
{ path: '/i/groups', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/user-groups.vue').then(m => m.default) }) },
{ path: '/i/groups/:groupId', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/user-group-editor.vue').then(m => m.default), groupId: route.params.groupId }) },
]}
: { path: '/', component: MkHome, children: [
{ path: '', name: 'index', component: MkHomeTimeline },
@ -156,12 +162,18 @@ init(async (launch, os) => {
{ path: '/explore', name: 'explore', component: () => import('../common/views/pages/explore.vue').then(m => m.default) },
{ path: '/explore/tags/:tag', name: 'explore-tag', props: true, component: () => import('../common/views/pages/explore.vue').then(m => m.default) },
{ path: '/i/favorites', component: () => import('./views/home/favorites.vue').then(m => m.default) },
{ path: '/i/pages', component: () => import('./views/home/pages.vue').then(m => m.default) },
{ path: '/i/pages', component: () => import('../common/views/pages/pages.vue').then(m => m.default) },
{ path: '/i/lists', component: () => import('../common/views/pages/user-lists.vue').then(m => m.default) },
{ path: '/i/lists/:listId', props: true, component: () => import('../common/views/pages/user-list-editor.vue').then(m => m.default) },
{ path: '/i/groups', component: () => import('../common/views/pages/user-groups.vue').then(m => m.default) },
{ path: '/i/groups/:groupId', props: true, component: () => import('../common/views/pages/user-group-editor.vue').then(m => m.default) },
{ path: '/i/follow-requests', component: () => import('../common/views/pages/follow-requests.vue').then(m => m.default) },
]},
{ path: '/@:user/pages/:page', props: true, component: () => import('./views/pages/page.vue').then(m => m.default) },
{ path: '/@:user/pages/:pageName/view-source', props: true, component: () => import('./views/pages/page-editor.vue').then(m => m.default) },
{ path: '/i/pages/new', component: () => import('./views/pages/page-editor.vue').then(m => m.default) },
{ path: '/i/pages/edit/:pageId', props: true, component: () => import('./views/pages/page-editor.vue').then(m => m.default) },
{ path: '/i/messaging/group/:group', component: MkMessagingRoom },
{ path: '/i/messaging/:user', component: MkMessagingRoom },
{ path: '/i/drive', component: MkDrive },
{ path: '/i/drive/folder/:folder', component: MkDrive },

View File

@ -1,7 +1,7 @@
<template>
<mk-window ref="window" width="500px" height="560px" :popout-url="popout" @closed="destroyDom">
<template #header><fa icon="comments"/> {{ $t('@.messaging') }}: <mk-user-name :user="user"/></template>
<x-messaging-room :user="user" :class="$style.content"/>
<template #header><fa icon="comments"/> {{ $t('@.messaging') }}: <mk-user-name v-if="user" :user="user"/><span v-else>{{ group.name }}</span></template>
<x-messaging-room :user="user" :group="group" :class="$style.content"/>
</mk-window>
</template>
@ -16,10 +16,14 @@ export default Vue.extend({
components: {
XMessagingRoom: () => import('../../../common/views/components/messaging-room.vue').then(m => m.default)
},
props: ['user'],
props: ['user', 'group'],
computed: {
popout(): string {
return `${url}/i/messaging/${getAcct(this.user)}`;
if (this.user) {
return `${url}/i/messaging/${getAcct(this.user)}`;
} else if (this.group) {
return `${url}/i/messaging/group/${this.group.id}`;
}
}
}
});

View File

@ -1,7 +1,7 @@
<template>
<mk-window ref="window" width="500px" height="560px" @closed="destroyDom">
<template #header :class="$style.header"><fa icon="comments"/>{{ $t('@.messaging') }}</template>
<x-messaging :class="$style.content" @navigate="navigate"/>
<x-messaging :class="$style.content" @navigate="navigate" @navigateGroup="navigateGroup"/>
</mk-window>
</template>
@ -20,6 +20,11 @@ export default Vue.extend({
this.$root.new(MkMessagingRoomWindow, {
user: user
});
},
navigateGroup(group) {
this.$root.new(MkMessagingRoomWindow, {
group: group
});
}
}
});

View File

@ -54,7 +54,7 @@
</div>
<mk-poll v-if="appearNote.poll" :note="appearNote"/>
<mk-url-preview v-for="url in urls" :url="url" :key="url" :detail="true"/>
<a class="location" v-if="appearNote.geo" :href="`https://maps.google.com/maps?q=${appearNote.geo.coordinates[1]},${appearNote.geo.coordinates[0]}`" target="_blank"><fa icon="map-marker-alt"/> {{ $t('location') }}</a>
<a class="location" v-if="appearNote.geo" :href="`https://maps.google.com/maps?q=${appearNote.geo.coordinates[1]},${appearNote.geo.coordinates[0]}`" rel="noopener" target="_blank"><fa icon="map-marker-alt"/> {{ $t('location') }}</a>
<div class="map" v-if="appearNote.geo" ref="map"></div>
<div class="renote" v-if="appearNote.renote">
<mk-note-preview :note="appearNote.renote"/>

View File

@ -32,7 +32,7 @@
<mk-media-list :media-list="appearNote.files"/>
</div>
<mk-poll v-if="appearNote.poll" :note="appearNote" ref="pollViewer"/>
<a class="location" v-if="appearNote.geo" :href="`https://maps.google.com/maps?q=${appearNote.geo.coordinates[1]},${appearNote.geo.coordinates[0]}`" target="_blank"><fa icon="map-marker-alt"/> 位置情報</a>
<a class="location" v-if="appearNote.geo" :href="`https://maps.google.com/maps?q=${appearNote.geo.coordinates[1]},${appearNote.geo.coordinates[0]}`" rel="noopener" target="_blank"><fa icon="map-marker-alt"/> 位置情報</a>
<div class="renote" v-if="appearNote.renote"><mk-note-preview :note="appearNote.renote"/></div>
<mk-url-preview v-for="url in urls" :url="url" :key="url" :compact="compact"/>
</div>

View File

@ -1,70 +0,0 @@
<template>
<mk-window ref="window" is-modal width="450px" height="500px" @closed="destroyDom">
<template #header><fa :icon="['far', 'envelope']"/> {{ $t('title') }}</template>
<div class="slpqaxdoxhvglersgjukmvizkqbmbokc">
<div v-for="req in requests">
<router-link :key="req.id" :to="req.follower | userPage">
<mk-user-name :user="req.follower"/>
</router-link>
<span>
<a @click="accept(req.follower)">{{ $t('accept') }}</a>|<a @click="reject(req.follower)">{{ $t('reject') }}</a>
</span>
</div>
</div>
</mk-window>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({
i18n: i18n('desktop/views/components/received-follow-requests-window.vue'),
data() {
return {
fetching: true,
requests: []
};
},
mounted() {
this.$root.api('following/requests/list').then(requests => {
this.fetching = false;
this.requests = requests;
});
},
methods: {
accept(user) {
this.$root.api('following/requests/accept', { userId: user.id }).then(() => {
this.requests = this.requests.filter(r => r.follower.id != user.id);
});
},
reject(user) {
this.$root.api('following/requests/reject', { userId: user.id }).then(() => {
this.requests = this.requests.filter(r => r.follower.id != user.id);
});
},
close() {
(this as any).$refs.window.close();
}
}
});
</script>
<style lang="stylus" scoped>
.slpqaxdoxhvglersgjukmvizkqbmbokc
padding 16px
> button
margin-bottom 16px
> div
display flex
padding 16px
border solid 1px var(--faceDivider)
border-radius 4px
> span
margin 0 0 0 auto
</style>

View File

@ -28,12 +28,19 @@
<i><fa icon="angle-right"/></i>
</router-link>
</li>
<li @click="list">
<p>
<li>
<router-link to="/i/lists">
<i><fa icon="list" fixed-width/></i>
<span>{{ $t('lists') }}</span>
<i><fa icon="angle-right"/></i>
</p>
</router-link>
</li>
<li>
<router-link to="/i/groups">
<i><fa :icon="faUsers" fixed-width/></i>
<span>{{ $t('groups') }}</span>
<i><fa icon="angle-right"/></i>
</router-link>
</li>
<li>
<router-link to="/i/pages">
@ -42,12 +49,12 @@
<i><fa icon="angle-right"/></i>
</router-link>
</li>
<li @click="followRequests" v-if="($store.state.i.isLocked || $store.state.i.carefulBot)">
<p>
<li v-if="($store.state.i.isLocked || $store.state.i.carefulBot)">
<router-link to="/i/follow-requests">
<i><fa :icon="['far', 'envelope']" fixed-width/></i>
<span>{{ $t('follow-requests') }}<i v-if="$store.state.i.pendingReceivedFollowRequestsCount">{{ $store.state.i.pendingReceivedFollowRequestsCount }}</i></span>
<i><fa icon="angle-right"/></i>
</p>
</router-link>
</li>
</ul>
<ul>
@ -96,12 +103,10 @@
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
import MkUserListsWindow from './user-lists-window.vue';
import MkFollowRequestsWindow from './received-follow-requests-window.vue';
// import MkSettingsWindow from './settings-window.vue';
import MkDriveWindow from './drive-window.vue';
import contains from '../../../common/scripts/contains';
import { faHome, faColumns } from '@fortawesome/free-solid-svg-icons';
import { faHome, faColumns, faUsers } from '@fortawesome/free-solid-svg-icons';
import { faMoon, faSun, faStickyNote } from '@fortawesome/free-regular-svg-icons';
export default Vue.extend({
@ -109,7 +114,7 @@ export default Vue.extend({
data() {
return {
isOpen: false,
faHome, faColumns, faMoon, faSun, faStickyNote
faHome, faColumns, faMoon, faSun, faStickyNote, faUsers
};
},
computed: {
@ -147,14 +152,6 @@ export default Vue.extend({
this.close();
this.$root.new(MkDriveWindow);
},
list() {
this.close();
this.$root.new(MkUserListsWindow);
},
followRequests() {
this.close();
this.$root.new(MkFollowRequestsWindow);
},
signout() {
this.$root.signout();
},

View File

@ -72,8 +72,6 @@
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
import MkUserListsWindow from './user-lists-window.vue';
import MkFollowRequestsWindow from './received-follow-requests-window.vue';
import MkSettingsWindow from './settings-window.vue';
import MkDriveWindow from './drive-window.vue';
import MkMessagingWindow from './messaging-window.vue';

View File

@ -1,24 +0,0 @@
<template>
<mk-window ref="window" width="450px" height="500px" @closed="destroyDom">
<template #header><fa icon="list"/> {{ list.name }}</template>
<x-editor :list="list"/>
</mk-window>
</template>
<script lang="ts">
import Vue from 'vue';
import XEditor from '../../../common/views/components/user-list-editor.vue';
export default Vue.extend({
components: {
XEditor
},
props: {
list: {
required: true
}
}
});
</script>

View File

@ -1,36 +0,0 @@
<template>
<mk-window ref="window" width="450px" height="500px" @closed="destroyDom">
<template #header><fa icon="list"/> {{ $t('title') }}</template>
<x-lists :class="$style.content" @choosen="choosen"/>
</mk-window>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
import MkUserListWindow from './user-list-window.vue';
export default Vue.extend({
i18n: i18n('desktop/views/components/user-lists-window.vue'),
components: {
XLists: () => import('../../../common/views/components/user-lists.vue').then(m => m.default)
},
methods: {
close() {
(this as any).$refs.window.close();
},
choosen(list) {
this.$root.new(MkUserListWindow, {
list
});
}
}
});
</script>
<style lang="stylus" module>
.content
height 100%
overflow auto
</style>

View File

@ -1,92 +0,0 @@
<template>
<div class="rknalgpo" v-if="!fetching">
<ui-button @click="create()"><fa :icon="faPlus"/></ui-button>
<sequential-entrance animation="entranceFromTop" delay="25">
<template v-for="page in pages">
<x-page-preview class="page" :page="page" :key="page.id"/>
</template>
</sequential-entrance>
<ui-button v-if="existMore" @click="fetchMore()">{{ $t('@.load-more') }}</ui-button>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
import Progress from '../../../common/scripts/loading';
import { faPlus } from '@fortawesome/free-solid-svg-icons';
import { faStickyNote } from '@fortawesome/free-regular-svg-icons';
import XPagePreview from '../../../common/views/components/page-preview.vue';
export default Vue.extend({
i18n: i18n(),
components: {
XPagePreview
},
data() {
return {
fetching: true,
pages: [],
existMore: false,
moreFetching: false,
faStickyNote, faPlus
};
},
created() {
this.fetch();
},
methods: {
fetch() {
Progress.start();
this.fetching = true;
this.$root.api('i/pages', {
limit: 11
}).then(pages => {
if (pages.length == 11) {
this.existMore = true;
pages.pop();
}
this.pages = pages;
this.fetching = false;
Progress.done();
});
},
fetchMore() {
this.moreFetching = true;
this.$root.api('i/pages', {
limit: 11,
untilId: this.pages[this.pages.length - 1].id
}).then(pages => {
if (pages.length == 11) {
this.existMore = true;
pages.pop();
} else {
this.existMore = false;
}
this.pages = this.pages.concat(pages);
this.moreFetching = false;
});
},
create() {
this.$router.push(`/i/pages/new`);
}
}
});
</script>
<style lang="stylus" scoped>
.rknalgpo
margin 0 auto
> * > .page
margin-bottom 8px
@media (min-width 500px)
> * > .page
margin-bottom 16px
</style>

View File

@ -4,7 +4,7 @@
<fa icon="exclamation-triangle"/> {{ $t('@.user-suspended') }}
</div>
<div class="is-remote" v-if="user.host != null" :class="{ shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners }">
<fa icon="exclamation-triangle"/> {{ $t('@.is-remote-user') }}<a :href="user.url" target="_blank">{{ $t('@.view-on-remote') }}</a>
<fa icon="exclamation-triangle"/> {{ $t('@.is-remote-user') }}<a :href="user.url" rel="nofollow noopener" target="_blank">{{ $t('@.view-on-remote') }}</a>
</div>
<div class="main">
<x-header class="header" :user="user"/>

View File

@ -1,7 +1,7 @@
<template>
<div class="header" :class="{ shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners }">
<div class="banner-container" :style="style">
<div class="banner" ref="banner" :style="style" @click="onBannerClick"></div>
<div class="banner" ref="banner" :style="style"></div>
<div class="fade"></div>
<div class="title">
<p class="name">
@ -105,14 +105,6 @@ export default Vue.extend({
if (blur <= 10) banner.style.filter = `blur(${blur}px)`;
},
onBannerClick() {
if (!this.$store.getters.isSignedIn || this.$store.state.i.id != this.user.id) return;
this.$updateBanner().then(i => {
this.user.bannerUrl = i.bannerUrl;
});
},
menu() {
this.$root.new(XUserMenu, {
source: this.$refs.menu,
@ -171,9 +163,6 @@ export default Vue.extend({
> .menu
height 100%
display block
position absolute
left -42px
padding 0 14px
color #fff
text-shadow 0 0 8px #000

View File

@ -1,6 +1,6 @@
<template>
<div class="mk-messaging-room-page">
<x-messaging-room v-if="user" :user="user" :is-naked="true"/>
<x-messaging-room v-if="user || group" :user="user" :group="group" :is-naked="true"/>
</div>
</template>
@ -19,7 +19,8 @@ export default Vue.extend({
data() {
return {
fetching: true,
user: null
user: null,
group: null
};
},
watch: {
@ -47,14 +48,25 @@ export default Vue.extend({
Progress.start();
this.fetching = true;
this.$root.api('users/show', parseAcct(this.$route.params.user)).then(user => {
this.user = user;
this.fetching = false;
if (this.$route.params.user) {
this.$root.api('users/show', parseAcct(this.$route.params.user)).then(user => {
this.user = user;
this.fetching = false;
document.title = this.$t('@.messaging') + ': ' + getUserName(this.user);
document.title = this.$t('@.messaging') + ': ' + getUserName(this.user);
Progress.done();
});
Progress.done();
});
} else {
this.$root.api('users/groups/show', { groupId: this.$route.params.group }).then(group => {
this.group = group;
this.fetching = false;
document.title = this.$t('@.messaging') + ': ' + this.group.name;
Progress.done();
});
}
}
}
});

View File

@ -4,7 +4,7 @@
<template #header><fa icon="comments"/>{{ $t('@.messaging') }}</template>
<template #func><button @click="add"><fa icon="plus"/></button></template>
<x-messaging ref="index" compact @navigate="navigate"/>
<x-messaging ref="index" compact @navigate="navigate" @navigateGroup="navigateGroup"/>
</ui-container>
</div>
</template>
@ -31,6 +31,11 @@ export default define({
user: user
});
},
navigateGroup(group) {
this.$root.new(MkMessagingRoomWindow, {
group: group
});
},
add() {
this.$root.new(MkMessagingWindow);
},

View File

@ -18,17 +18,16 @@ import MkDrive from './views/pages/drive.vue';
import MkWidgets from './views/pages/widgets.vue';
import MkMessaging from './views/pages/messaging.vue';
import MkMessagingRoom from './views/pages/messaging-room.vue';
import MkReceivedFollowRequests from './views/pages/received-follow-requests.vue';
import MkNote from './views/pages/note.vue';
import MkSearch from './views/pages/search.vue';
import MkFavorites from './views/pages/favorites.vue';
import MkUserLists from './views/pages/user-lists.vue';
import MkUserList from './views/pages/user-list.vue';
import UI from './views/pages/ui.vue';
import MkReversi from './views/pages/games/reversi.vue';
import MkTag from './views/pages/tag.vue';
import MkShare from '../common/views/pages/share.vue';
import MkFollow from '../common/views/pages/follow.vue';
import MkNotFound from '../common/views/pages/not-found.vue';
import DeckColumn from '../common/views/deck/deck.column-template.vue';
import PostForm from './views/components/post-form-dialog.vue';
import FileChooser from './views/components/drive-file-chooser.vue';
@ -125,9 +124,14 @@ init((launch, os) => {
{ path: '/search', component: () => import('../common/views/deck/deck.search-column.vue').then(m => m.default) },
{ path: '/tags/:tag', name: 'tag', component: () => import('../common/views/deck/deck.hashtag-column.vue').then(m => m.default) },
{ path: '/featured', name: 'featured', component: () => import('../common/views/deck/deck.featured-column.vue').then(m => m.default) },
{ path: '/explore', name: 'explore', component: () => import('../common/views/deck/deck.explore-column.vue').then(m => m.default) },
{ path: '/explore/tags/:tag', name: 'explore-tag', props: true, component: () => import('../common/views/deck/deck.explore-column.vue').then(m => m.default) },
{ path: '/i/favorites', component: () => import('../common/views/deck/deck.favorites-column.vue').then(m => m.default) }
{ path: '/explore', name: 'explore', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/explore.vue').then(m => m.default) }) },
{ path: '/explore/tags/:tag', name: 'explore-tag', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/explore.vue').then(m => m.default), tag: route.params.tag }) },
{ path: '/i/favorites', component: () => import('../common/views/deck/deck.favorites-column.vue').then(m => m.default) },
{ path: '/i/pages', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/pages.vue').then(m => m.default) }) },
{ path: '/i/lists', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/user-lists.vue').then(m => m.default) }) },
{ path: '/i/lists/:listId', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/user-list-editor.vue').then(m => m.default), listId: route.params.listId }) },
{ path: '/i/groups', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/user-groups.vue').then(m => m.default) }) },
{ path: '/i/groups/:groupId', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/user-group-editor.vue').then(m => m.default), groupId: route.params.groupId }) },
]}]
: [
{ path: '/', name: 'index', component: MkIndex },
@ -135,12 +139,15 @@ init((launch, os) => {
{ path: '/signup', name: 'signup', component: MkSignup },
{ path: '/i/settings', name: 'settings', component: () => import('./views/pages/settings.vue').then(m => m.default) },
{ path: '/i/favorites', name: 'favorites', component: MkFavorites },
{ path: '/i/pages', name: 'pages', component: () => import('./views/pages/pages.vue').then(m => m.default) },
{ path: '/i/lists', name: 'user-lists', component: MkUserLists },
{ path: '/i/lists/:list', name: 'user-list', component: MkUserList },
{ path: '/i/received-follow-requests', name: 'received-follow-requests', component: MkReceivedFollowRequests },
{ path: '/i/pages', name: 'pages', component: UI, props: route => ({ component: () => import('../common/views/pages/pages.vue').then(m => m.default) }) },
{ path: '/i/lists', name: 'user-lists', component: UI, props: route => ({ component: () => import('../common/views/pages/user-lists.vue').then(m => m.default) }) },
{ path: '/i/lists/:list', component: UI, props: route => ({ component: () => import('../common/views/pages/user-list-editor.vue').then(m => m.default), listId: route.params.list }) },
{ path: '/i/groups', name: 'user-groups', component: UI, props: route => ({ component: () => import('../common/views/pages/user-groups.vue').then(m => m.default) }) },
{ path: '/i/groups/:group', component: UI, props: route => ({ component: () => import('../common/views/pages/user-group-editor.vue').then(m => m.default), groupId: route.params.group }) },
{ path: '/i/follow-requests', name: 'follow-requests', component: UI, props: route => ({ component: () => import('../common/views/pages/follow-requests.vue').then(m => m.default) }) },
{ path: '/i/widgets', name: 'widgets', component: MkWidgets },
{ path: '/i/messaging', name: 'messaging', component: MkMessaging },
{ path: '/i/messaging/group/:group', component: MkMessagingRoom },
{ path: '/i/messaging/:user', component: MkMessagingRoom },
{ path: '/i/drive', name: 'drive', component: MkDrive },
{ path: '/i/drive/folder/:folder', component: MkDrive },
@ -151,8 +158,8 @@ init((launch, os) => {
{ path: '/search', component: MkSearch },
{ path: '/tags/:tag', component: MkTag },
{ path: '/featured', name: 'featured', component: () => import('./views/pages/featured.vue').then(m => m.default) },
{ path: '/explore', name: 'explore', component: () => import('./views/pages/explore.vue').then(m => m.default) },
{ path: '/explore/tags/:tag', name: 'explore-tag', props: true, component: () => import('./views/pages/explore.vue').then(m => m.default) },
{ path: '/explore', name: 'explore', component: UI, props: route => ({ component: () => import('../common/views/pages/explore.vue').then(m => m.default) }) },
{ path: '/explore/tags/:tag', name: 'explore-tag', component: UI, props: route => ({ component: () => import('../common/views/pages/explore.vue').then(m => m.default), tag: route.params.tag }) },
{ path: '/share', component: MkShare },
{ path: '/games/reversi/:game?', name: 'reversi', component: MkReversi },
{ path: '/@:user', name: 'user', component: () => import('./views/pages/user/index.vue').then(m => m.default), children: [

View File

@ -7,6 +7,7 @@
</div>
<a class="kkjnbbplepmiyuadieoenjgutgcmtsvu" v-else
:href="video.url"
rel="nofollow noopener"
target="_blank"
:style="imageStyle"
:title="video.name"

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