Compare commits

...

152 Commits

Author SHA1 Message Date
syuilo
d5ab6b41c9 10.42.2 2018-11-06 20:54:15 +09:00
syuilo
ffdd0b7de7 [API] 文字列での真理値表現に対応
multipart/formdata では文字列しか送れないっぽい?
2018-11-06 20:53:50 +09:00
syuilo
1808eb6eee 10.42.1 2018-11-06 20:49:03 +09:00
syuilo
438563b505 [API] Fix bug 2018-11-06 20:47:56 +09:00
syuilo
92dfcdad57 Fix #3141 2018-11-06 20:47:07 +09:00
syuilo
c178cfabfa 10.42.0 2018-11-06 15:52:28 +09:00
syuilo
260e4c955d 🎨 2018-11-06 15:51:18 +09:00
syuilo
0c46f5ce70 Clean up 2018-11-06 15:51:05 +09:00
syuilo
6d67cd07a0 [Client] Use dynamic import to reduce bundle size 2018-11-06 15:37:41 +09:00
syuilo
fb8af53751 [Client] Improve usability & Refactoring 2018-11-06 15:08:22 +09:00
syuilo
37999f4af7 [API] Implement notes/watching/ 2018-11-06 14:58:20 +09:00
MeiMei
3b6ab327c1 Twemojiで合字に対応 (#3140)
* Twemojiで合字に対応

* split emoji regex
2018-11-06 14:09:40 +09:00
syuilo
d3ff3a7d54 10.41.0 2018-11-06 08:06:08 +09:00
syuilo
cf36106520 🎨 2018-11-06 08:04:34 +09:00
syuilo
1642fbec31 [Client] カスタム絵文字サジェストの結果をアルファベット順にソートするように 2018-11-06 08:02:19 +09:00
syuilo
b195fd8145 🎨 2018-11-06 07:57:16 +09:00
MeiMei
5f59b980a7 Fix: download file (#3138)
* Fix: url download

* not explicitly close on end

* resolve on stream finish

* remove unnecessary code

* reject on file error
2018-11-06 07:53:03 +09:00
syuilo
2a5c19cd01 リモートのファイルをキャッシュするかどうかの設定をDBに保存するように 2018-11-06 07:52:13 +09:00
syuilo
42e007ddb7 🎨 2018-11-06 07:28:49 +09:00
syuilo
756dc397d9 🎨 2018-11-06 07:22:39 +09:00
syuilo
8f714b5b12 ドライブ容量の設定をDBに保存するようにしたりリファクタリングしたり 2018-11-06 07:14:43 +09:00
syuilo
06bb2a1c7c Clean up 2018-11-06 06:25:35 +09:00
syuilo
ac50bb9225 Resolve #3137 2018-11-06 06:24:31 +09:00
syuilo
8fd95de25b 整理 2018-11-06 06:12:51 +09:00
dependabot[bot]
0e14b2eba4 Update file-type requirement from 10.3.0 to 10.4.0 (#3135)
Updates the requirements on [file-type](https://github.com/sindresorhus/file-type) to permit the latest version.
- [Release notes](https://github.com/sindresorhus/file-type/releases)
- [Commits](https://github.com/sindresorhus/file-type/commits/v10.4.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-06 06:08:41 +09:00
dependabot[bot]
08413a7550 Update webpack requirement from 4.23.1 to 4.25.1 (#3136)
Updates the requirements on [webpack](https://github.com/webpack/webpack) to permit the latest version.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/commits/v4.25.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-06 05:35:53 +09:00
syuilo
5e0f2a5b06 [Client] Fix bug 2018-11-06 04:10:30 +09:00
syuilo
3b505709c6 10.40.1 2018-11-06 04:02:04 +09:00
syuilo
af32d1f81e [Client] Fix bug 2018-11-06 04:01:22 +09:00
syuilo
67d8773e38 [Client] Fix bug 2018-11-06 03:59:58 +09:00
syuilo
e445d39c2f [Client] Use v-if instaed of v-show 2018-11-06 03:59:02 +09:00
syuilo
961ed969db メッセージでのカスタム絵文字対応 2018-11-06 03:57:02 +09:00
syuilo
e9a3495225 Resolve #3132 2018-11-06 03:48:23 +09:00
Aya Morisawa
6c5a78aeb2 Fix #3133 (#3134) 2018-11-06 03:31:16 +09:00
syuilo
34e249317a 10.40.0 2018-11-06 02:06:15 +09:00
syuilo
6d8ea89f09 Resolve #3126 2018-11-06 02:05:16 +09:00
syuilo
64f89ba13e Better error code 2018-11-06 01:57:31 +09:00
syuilo
f6b2f76bbf 10.39.1 2018-11-06 01:52:39 +09:00
syuilo
1235bef038 [API] Fix bug 2018-11-06 01:51:42 +09:00
syuilo
2e11f3a843 Clean up 2018-11-06 01:49:35 +09:00
syuilo
84b7e0bb7d 🎨 2018-11-06 01:48:33 +09:00
syuilo
9f5dc2c0df [WIP] Use FontAwesome Component for Vue (#3127)
* wip

* Rename

* Clean up

* Clean up

* wip

* wip

* Enable tree shaking

* ✌️

* ✌️

* wip

* wip

* Clean up
2018-11-06 01:40:11 +09:00
syuilo
e640dbc501 🎨 2018-11-05 22:45:45 +09:00
syuilo
85db090d9f 🎨 2018-11-05 22:42:08 +09:00
syuilo
9f2d8e1d51 10.39.0 2018-11-05 21:07:24 +09:00
syuilo
0c98a90b75 [Client] カスタム絵文字にホバーしたときに拡大するエフェクトを追加 2018-11-05 21:04:19 +09:00
syuilo
0047920c1a Merge pull request #3117 from syuilo/twemoji
Use Twemoji
2018-11-05 20:52:55 +09:00
syuilo
e4bb534f20 Better emoji regexp 2018-11-05 20:49:17 +09:00
syuilo
3fc04fcdc5 Improve readdability 2018-11-05 20:49:02 +09:00
syuilo
e542dcac30 Fix test 2018-11-05 20:40:39 +09:00
syuilo
a0b13505a0 Insert missing spaces 2018-11-05 20:15:09 +09:00
syuilo
389f9bfea2 Add test 2018-11-05 20:14:49 +09:00
syuilo
630a534cee Fix test 2018-11-05 20:10:28 +09:00
syuilo
5744c391e6 Revert "Fix test fails"
This reverts commit b9b05a7401.
2018-11-05 20:10:00 +09:00
Acid Chicken (硫酸鶏)
b9b05a7401 Fix test fails 2018-11-05 19:50:38 +09:00
syuilo
359470a263 Fix bug 2018-11-05 19:40:09 +09:00
syuilo
3fe934ee62 Better alt value 2018-11-05 19:33:28 +09:00
syuilo
3abe632f06 Clean up 2018-11-05 19:29:50 +09:00
syuilo
65961bc15b Refactoring & 設定でTwemojiを使うかどうか切り替えられるように 2018-11-05 19:20:35 +09:00
Acid Chicken (硫酸鶏)
12f932d48a Update CI configuration (#3120)
* Update config.yml

* Add `npm prune` command

refs: https://misskey.xyz/notes/5bd9b87168b2a30045edb3aa

* Ensure package-lock.json exists
2018-11-05 17:38:57 +09:00
Acid Chicken (硫酸鶏)
54e9147782 Refactoring codes
refs: https://github.com/syuilo/misskey/pull/3117#pullrequestreview-171437187
2018-11-05 17:04:17 +09:00
Acid Chicken (硫酸鶏)
31b7626d01 Make code better
refs: https://github.com/syuilo/misskey/pull/3117#pullrequestreview-171423739
refs: https://github.com/syuilo/misskey/pull/3117#pullrequestreview-171424596
refs: https://github.com/syuilo/misskey/pull/3117#pullrequestreview-171425303
2018-11-05 16:19:14 +09:00
Acid Chicken (硫酸鶏)
200ebefe92 Add support for unicode emojis
refs: https://github.com/syuilo/misskey/pull/3117#issuecomment-435745613
2018-11-05 15:15:37 +09:00
syuilo
9d29a2e85a 10.38.8 2018-11-05 13:47:57 +09:00
syuilo
c62a225542 oops 2018-11-05 13:46:46 +09:00
syuilo
d5d995a3e6 Refactor 2018-11-05 13:38:50 +09:00
Acid Chicken (硫酸鶏)
b7f10fdc10 Fix bug
refs: https://github.com/syuilo/misskey/pull/3117#discussion_r230624389
2018-11-05 13:24:54 +09:00
syuilo
cbba03b376 [Client] Fix bug 2018-11-05 13:23:30 +09:00
syuilo
f84e9c7dc8 絵文字サジェストでスペースを挿入しないように 2018-11-05 12:35:50 +09:00
syuilo
a22ddb1fb9 ✌️ 2018-11-05 11:58:41 +09:00
Acid Chicken (硫酸鶏)
0d23ce3d45 Make /api/v1/instance and /api/v1/custom_emojis better (#3118)
* Separate commits

From commit dca110ebaa.

* Re-separate commits

From commit 9719387bee.
2018-11-05 11:57:17 +09:00
Acid Chicken (硫酸鶏)
9719387bee Re-separate commits 2018-11-05 11:51:14 +09:00
Acid Chicken (硫酸鶏)
dca110ebaa Separate commits
Flash Back 90's
2018-11-05 11:39:13 +09:00
Acid Chicken (硫酸鶏)
136f23c7ad Merge branch 'develop' into twemoji 2018-11-05 11:21:34 +09:00
Acid Chicken (硫酸鶏)
0963e6d6e1 Use Twemoji 2018-11-05 11:19:40 +09:00
syuilo
712802e682 10.38.7 2018-11-05 11:11:23 +09:00
syuilo
abe99c3c73 Update locales/ja-JP.yml 2018-11-05 11:10:02 +09:00
syuilo
d7a3b71028 投稿の最大文字数情報を設定ファイルではなくDBに保存するように 2018-11-05 11:09:05 +09:00
syuilo
10c434f24a Remove Travis
Closes #3109
2018-11-05 10:52:07 +09:00
syuilo
fe46c53ea6 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2018-11-05 10:48:51 +09:00
syuilo
cdd123dfd3 [doc] specify node version 2018-11-05 10:48:40 +09:00
Acid Chicken (硫酸鶏)
a1a3ee44b5 Implement /api/v1/custom_emojis (#3116) 2018-11-05 10:45:57 +09:00
Acid Chicken (硫酸鶏)
4e7fbd8967 Implement /api/v1/custom_emojis 2018-11-05 10:42:46 +09:00
syuilo
a86c419f95 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2018-11-05 10:40:15 +09:00
syuilo
e3ec0ad97e [Client] Improve admin panel usability 2018-11-05 10:40:01 +09:00
Acid Chicken (硫酸鶏)
75791981ce Fix #3115 2018-11-05 10:34:53 +09:00
syuilo
e813fe16b9 [API] Better validation of admin/emoji/add 2018-11-05 10:33:49 +09:00
syuilo
42ac7b954d Improve admin panel usability 2018-11-05 10:32:45 +09:00
syuilo
c1bbf5dab6 [Client] Fix error 2018-11-05 10:29:57 +09:00
Aya Morisawa
e16dc2a910 Update README.md (#3112) 2018-11-05 01:57:08 +09:00
syuilo
e236c05d79 10.38.6 2018-11-05 01:43:31 +09:00
syuilo
454c1e3faf [API] Fix bug 2018-11-05 01:42:41 +09:00
syuilo
43daf814df [Client] 絵文字登録フォームに便利情報を表示 2018-11-05 01:33:06 +09:00
syuilo
c40b630530 10.38.5 2018-11-04 23:20:06 +09:00
syuilo
7fc0698ecf 🎨 2018-11-04 23:15:46 +09:00
syuilo
4f3c8b940e [API] Fix #3099 2018-11-04 23:13:35 +09:00
syuilo
1855ab60f1 Resolve #3098 2018-11-04 23:00:43 +09:00
syuilo
af4f1a7bd6 Clean up 2018-11-04 22:05:42 +09:00
Acid Chicken (硫酸鶏)
8646a9c49c Add GitHub auth (#3095) 2018-11-04 22:03:55 +09:00
syuilo
8d7c033cf5 Clean up 2018-11-04 21:21:34 +09:00
syuilo
b8900e32de 🎨 2018-11-04 21:14:17 +09:00
syuilo
d48c25d2c9 [API] Fix #3097 2018-11-04 21:11:54 +09:00
Acid Chicken (硫酸鶏)
a87c5899c5 Fix typo 2018-11-04 20:08:31 +09:00
Acid Chicken (硫酸鶏)
147ad69864 Revert "Add GitHub auth"
This reverts commit c146006476.
2018-11-04 19:22:04 +09:00
Acid Chicken (硫酸鶏)
c146006476 Add GitHub auth 2018-11-04 19:17:30 +09:00
syuilo
a0f10d7ca1 10.38.4 2018-11-04 18:38:04 +09:00
syuilo
299b91edc4 [API] Improve admin/emoji/add 2018-11-04 18:37:12 +09:00
syuilo
95c89ca6db RE: [Client] Fix bug 2018-11-04 18:36:19 +09:00
syuilo
7fe0d71e7f [Client] Fix bug 2018-11-04 18:35:55 +09:00
syuilo
fbbb506e86 🎨 2018-11-04 18:31:27 +09:00
syuilo
ec80b06a45 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2018-11-04 18:24:20 +09:00
syuilo
41e1619f1f [Client] Fix bug 2018-11-04 18:24:08 +09:00
syuilo
ba6a9c6a93 Merge pull request #3092 from syuilo/l10n_develop
New Crowdin translations
2018-11-04 18:22:19 +09:00
MeiMei
18571c52fb Fix: emoji regex (#3093) 2018-11-04 17:36:37 +09:00
syuilo
5d5dfeaa83 New translations ja-JP.yml (Japanese, Kansai) 2018-11-04 17:11:19 +09:00
syuilo
3669d8c0f3 New translations ja-JP.yml (Japanese, Kansai) 2018-11-04 17:01:11 +09:00
syuilo
69d72819c6 10.38.3 2018-11-04 15:18:37 +09:00
syuilo
54dcc10250 Fix bug for Mastodon(?) 2018-11-04 15:17:52 +09:00
syuilo
1edfce8f73 [Client] スマホ/タブレットからでも管理者ページを使えるように 2018-11-04 15:16:05 +09:00
syuilo
675e573a8c 🎨 2018-11-04 14:23:28 +09:00
syuilo
1080fa63a9 10.38.2 2018-11-04 11:09:31 +09:00
syuilo
8047086988 Good bye package-lock 2018-11-04 11:08:46 +09:00
syuilo
449b9f7fa0 [Client] Improve admin panel 2018-11-04 11:08:03 +09:00
syuilo
b7a15bf6ca 絵文字を作成した/更新した時にupdateAtを更新するように 2018-11-04 10:42:16 +09:00
syuilo
7c3873887d 10.38.1 2018-11-04 03:45:05 +09:00
syuilo
247ea4cf12 Merge pull request #3083 from syuilo/l10n_develop
New Crowdin translations
2018-11-04 03:44:30 +09:00
syuilo
0b7af5c669 [Client] Fix bug 2018-11-04 03:44:06 +09:00
syuilo
2b62a4e2e5 New translations ja-JP.yml (English) 2018-11-04 03:42:45 +09:00
MeiMei
65bfa3c0d6 Fix: update_client_setting (#3086) 2018-11-04 03:33:37 +09:00
syuilo
84db15694d Do not send needless emojis in note
投稿作成時に含まれている絵文字を保存しておくように

SEE: https://github.com/syuilo/misskey/pull/3085#issuecomment-435608434
2018-11-04 03:32:20 +09:00
syuilo
746189ba37 New translations ja-JP.yml (Norwegian) 2018-11-04 03:23:44 +09:00
syuilo
74e845b3ac New translations ja-JP.yml (Dutch) 2018-11-04 03:23:39 +09:00
syuilo
90fe70540e New translations ja-JP.yml (Japanese, Kansai) 2018-11-04 03:23:36 +09:00
syuilo
f28af75191 New translations ja-JP.yml (Spanish) 2018-11-04 03:23:31 +09:00
syuilo
924bb2bc70 New translations ja-JP.yml (Russian) 2018-11-04 03:23:26 +09:00
syuilo
19d60f3d51 New translations ja-JP.yml (Portuguese) 2018-11-04 03:23:22 +09:00
syuilo
6903476868 New translations ja-JP.yml (Polish) 2018-11-04 03:23:16 +09:00
syuilo
cf0dccc209 New translations ja-JP.yml (Korean) 2018-11-04 03:23:10 +09:00
syuilo
cfd959129d New translations ja-JP.yml (Italian) 2018-11-04 03:23:06 +09:00
syuilo
819287951c New translations ja-JP.yml (German) 2018-11-04 03:23:02 +09:00
syuilo
e136193925 New translations ja-JP.yml (French) 2018-11-04 03:22:57 +09:00
syuilo
8c631864d9 New translations ja-JP.yml (English) 2018-11-04 03:22:53 +09:00
syuilo
d7d0f6ae2e New translations ja-JP.yml (Chinese Simplified) 2018-11-04 03:22:47 +09:00
syuilo
b83b3fb9d1 New translations ja-JP.yml (Catalan) 2018-11-04 03:22:43 +09:00
syuilo
dfce5bc0af [Client] Improve Emoji management page of admin panel 2018-11-04 03:18:57 +09:00
syuilo
3487ddabea [API] Implement some Emoji APIs 2018-11-04 03:18:32 +09:00
syuilo
2dbff75e7a New translations ja-JP.yml (French) 2018-11-04 02:53:30 +09:00
syuilo
02465ded9f New translations ja-JP.yml (French) 2018-11-04 02:41:50 +09:00
syuilo
ffcd387945 New translations ja-JP.yml (French) 2018-11-04 02:31:36 +09:00
syuilo
4806346707 New translations ja-JP.yml (French) 2018-11-04 02:21:09 +09:00
MeiMei
31c3f6abf7 Fix: welcome-timeline (#3084) 2018-11-04 01:49:08 +09:00
syuilo
83e47fdd60 New translations ja-JP.yml (English) 2018-11-04 01:21:56 +09:00
288 changed files with 2883 additions and 19700 deletions

View File

@@ -23,6 +23,10 @@ jobs:
executor: default executor: default
steps: steps:
- checkout - checkout
- run:
name: Ensure package-lock.json
command: |
[ ! -e package-lock.json ] && echo '{}' > package-lock.json
- restore_cache: - restore_cache:
name: Restore npm package caches name: Restore npm package caches
keys: keys:
@@ -35,11 +39,12 @@ jobs:
name: Install Dependencies name: Install Dependencies
command: | command: |
npm install npm install
npm prune
- run: - run:
name: Configure name: Configure
command: | command: |
cp .ci/default.yml .config cp .circleci/misskey/default.yml .config
cp .ci/test.yml .config cp .circleci/misskey/test.yml .config
- run: - run:
name: Build name: Build
command: | command: |
@@ -50,8 +55,8 @@ jobs:
key: npm-v1-arch-{{ arch }}-env-{{ .Environment.variableName }}-package-{{ checksum "package.json" }}-lock-{{ checksum "package-lock.json" }}-ls-{{ checksum "ls" }} key: npm-v1-arch-{{ arch }}-env-{{ .Environment.variableName }}-package-{{ checksum "package.json" }}-lock-{{ checksum "package-lock.json" }}-ls-{{ checksum "ls" }}
paths: paths:
- node_modules - node_modules
- store_artifacts: # - store_artifacts:
path: built # path: built
- persist_to_workspace: - persist_to_workspace:
root: . root: .
paths: paths:
@@ -98,7 +103,6 @@ jobs:
name: Build name: Build
command: | command: |
docker build . | tee docker.log docker build . | tee docker.log
tail -n 1 docker.log | read __Successfully __built tag
- when: - when:
condition: <<parameters.with_deploy>> condition: <<parameters.with_deploy>>
steps: steps:
@@ -107,6 +111,7 @@ jobs:
command: | command: |
if [ "$DOCKERHUB_USERNAME$DOCKERHUB_PASSWORD" ] if [ "$DOCKERHUB_USERNAME$DOCKERHUB_PASSWORD" ]
then then
tail -n 1 docker.log | read __Successfully __built tag
docker tag $tag misskey/misskey docker tag $tag misskey/misskey
docker login -u $DOCKERHUB_USERNAME -p $DOCKERHUB_PASSWORD docker login -u $DOCKERHUB_USERNAME -p $DOCKERHUB_PASSWORD
docker push misskey/misskey docker push misskey/misskey
@@ -126,10 +131,13 @@ workflows:
without_redis: "true" without_redis: "true"
requires: requires:
- build - build
- docker:
filters: filters:
branches: branches:
ignore: master only: master
# - docker:
# filters:
# branches:
# ignore: master
- docker: - docker:
with_deploy: "true" with_deploy: "true"
filters: filters:

View File

@@ -1,6 +1,3 @@
name: example-instance-name # Name of your instance
description: example-description # Description of your instance
maintainer: maintainer:
name: example-maitainer-name # Your name name: example-maitainer-name # Your name
url: http://example.com/ # Your contact (http or mailto) url: http://example.com/ # Your contact (http or mailto)
@@ -25,7 +22,7 @@ url: https://example.tld/
# +------+ |+-------------+ +----------------+| # +------+ |+-------------+ +----------------+|
# +---------------------------------------+ # +---------------------------------------+
# #
# You need to setup reverse proxy. (eg. Nginx) # You need to setup reverse proxy. (eg. nginx)
# You do not define 'https' section. # You do not define 'https' section.
# Option 2: Standalone # Option 2: Standalone
@@ -60,21 +57,6 @@ mongodb:
user: example-misskey-user user: example-misskey-user
pass: example-misskey-pass pass: example-misskey-pass
# Drive capacity of a local user (MB)
localDriveCapacityMb: 256
# Drive capacity of a remote user (MB)
remoteDriveCapacityMb: 8
# If enabled:
# Server will not cache remote files (Using direct link instead).
# You can save your storage.
#
# NOTE:
# * Users cannot see remote images when they turn off "Show media from a remote server" setting.
# * Since thumbnails are not provided, traffic increases.
preventCacheRemoteFiles: false
drive: drive:
storage: 'db' storage: 'db'
@@ -113,6 +95,10 @@ drive:
# accessKey: XXX # accessKey: XXX
# secretKey: YYY # secretKey: YYY
# If enabled:
# The first account created is automatically marked as Admin.
autoAdmin: true
# #
# Below settings are optional # Below settings are optional
# #
@@ -148,6 +134,12 @@ drive:
# consumer_key: example-twitter-consumer-key # consumer_key: example-twitter-consumer-key
# consumer_secret: example-twitter-consumer-secret-key # consumer_secret: example-twitter-consumer-secret-key
# GitHub integration
# You need to set the oauth callback url as : https://<your-misskey-instance>/api/gh/cb
#github:
# client_id: example-github-client-id
# client_secret: example-github-client-secret
# Ghost # Ghost
# Ghost account is an account used for the purpose of delegating # Ghost account is an account used for the purpose of delegating
# followers when putting users in the list. # followers when putting users in the list.
@@ -164,6 +156,3 @@ drive:
# external: true # external: true
# engine: http://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}} # engine: http://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}
# timeout: 300000 # timeout: 300000
# Max allowed note text length in charactors
maxNoteTextLength: 1000

1
.npmrc
View File

@@ -1 +1,2 @@
save-exact = true save-exact = true
package-lock = false

View File

@@ -1,41 +0,0 @@
# travis file
# https://docs.travis-ci.com/user/customizing-the-build
notifications:
email: false
branches:
except:
- l10n_master
language: node_js
node_js:
- 11.0.0
env:
- CXX=g++-4.8 NODE_ENV=production
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.8
cache:
directories:
- node_modules
services:
- mongodb
- redis-server
before_script:
- npm install
# 設定ファイルを配置
- cp ./.ci/default.yml ./.config
- cp ./.ci/test.yml ./.config
- travis_wait npm run build

View File

@@ -23,5 +23,5 @@ Please use [Crowdin](https://crowdin.com/project/misskey) for localization.
* Test codes are located in `/test`. * Test codes are located in `/test`.
## Continuous integration ## Continuous integration
Misskey uses Travis for automated test. Misskey uses CircleCI for automated test.
Configuration files are located in `/.travis`. Configuration files are located in `/.circleci`.

View File

@@ -4,7 +4,6 @@
================================================================ ================================================================
[![CircleCI](https://circleci.com/gh/syuilo/misskey.svg?style=svg)](https://circleci.com/gh/syuilo/misskey) [![CircleCI](https://circleci.com/gh/syuilo/misskey.svg?style=svg)](https://circleci.com/gh/syuilo/misskey)
[![][travis-badge]][travis-link]
[![][dependencies-badge]][dependencies-link] [![][dependencies-badge]][dependencies-link]
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
@@ -44,7 +43,7 @@ Easiest way to tell your emotions. Misskey allows you to add various type of rea
<h3 align="left">Interface</h3> <h3 align="left">Interface</h3>
<p align="left"> <p align="left">
No UI fits for everyone. Therefore, Misskey has a highly customizable UI for your taste. You can edit layouts of your timeline, place selectable widgets you can easily move and create your unique home as this place will be your home. Highly customizable UI for your taste. We understand no UI fits for everyone. You can edit layouts of your timeline, place selectable widgets you can easily move and create your unique home as this place will be your home.
</p> </p>
--- ---
@@ -124,8 +123,6 @@ Misskey is an open-source software licensed under the [GNU AGPLv3](LICENSE).
[agpl-3.0]: https://www.gnu.org/licenses/agpl-3.0.en.html [agpl-3.0]: https://www.gnu.org/licenses/agpl-3.0.en.html
[agpl-3.0-badge]: https://img.shields.io/badge/license-AGPL--3.0-444444.svg?style=flat-square [agpl-3.0-badge]: https://img.shields.io/badge/license-AGPL--3.0-444444.svg?style=flat-square
[travis-link]: https://travis-ci.org/syuilo/misskey
[travis-badge]: http://img.shields.io/travis/syuilo/misskey/master.svg?style=flat-square
[dependencies-link]: https://david-dm.org/syuilo/misskey [dependencies-link]: https://david-dm.org/syuilo/misskey
[dependencies-badge]: https://img.shields.io/david/syuilo/misskey.svg?style=flat-square [dependencies-badge]: https://img.shields.io/david/syuilo/misskey.svg?style=flat-square

View File

@@ -22,7 +22,7 @@ adduser --disabled-password --disabled-login misskey
Please install and setup these softwares: Please install and setup these softwares:
#### Dependencies :package: #### Dependencies :package:
* **[Node.js](https://nodejs.org/en/)** * **[Node.js](https://nodejs.org/en/)** >= 10.0.0
* **[MongoDB](https://www.mongodb.com/)** >= 3.6 * **[MongoDB](https://www.mongodb.com/)** >= 3.6
##### Optional ##### Optional

View File

@@ -22,7 +22,7 @@ adduser --disabled-password --disabled-login misskey
これらのソフトウェアをインストール・設定してください: これらのソフトウェアをインストール・設定してください:
#### 依存関係 :package: #### 依存関係 :package:
* **[Node.js](https://nodejs.org/en/)** * **[Node.js](https://nodejs.org/en/)** (10.0.0以上)
* **[MongoDB](https://www.mongodb.com/)** (3.6以上) * **[MongoDB](https://www.mongodb.com/)** (3.6以上)
##### オプション ##### オプション

View File

@@ -21,7 +21,6 @@ import * as htmlmin from 'gulp-htmlmin';
const uglifyes = require('uglify-es'); const uglifyes = require('uglify-es');
const locales = require('./locales'); const locales = require('./locales');
import { fa } from './src/misc/fa';
const uglify = uglifyComposer(uglifyes, console); const uglify = uglifyComposer(uglifyes, console);
@@ -164,8 +163,7 @@ gulp.task('build:client:pug', [
gulp.src('./src/client/app/base.pug') gulp.src('./src/client/app/base.pug')
.pipe(pug({ .pipe(pug({
locals: { locals: {
themeColor: constants.themeColor, themeColor: constants.themeColor
facss: fa.dom.css()
} }
})) }))
.pipe(htmlmin({ .pipe(htmlmin({

View File

@@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
aliases-desc: "スペースで区切って複数設定できます。" aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL" url: "絵文字画像URL"
add: "追加" add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue: admin/views/announcements.vue:
announcements: "お知らせ" announcements: "お知らせ"
save: "保存" save: "保存"

View File

@@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
aliases-desc: "スペースで区切って複数設定できます。" aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL" url: "絵文字画像URL"
add: "追加" add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue: admin/views/announcements.vue:
announcements: "お知らせ" announcements: "お知らせ"
save: "保存" save: "保存"

View File

@@ -1010,11 +1010,15 @@ admin/views/emoji.vue:
add-emoji: add-emoji:
title: "Add emoji" title: "Add emoji"
name: "Emoji name" name: "Emoji name"
name-desc: "a~z 0~9 _ の文字が使えます。" name-desc: "You can use the characters a~z 0~9 _"
aliases: "Aliases" aliases: "Aliases"
aliases-desc: "スペースで区切って複数設定できます。" aliases-desc: "You can add more than one, separated by spaces."
url: "Image URL" url: "Image URL"
add: "Add" add: "Add"
emojis:
title: "Emojis"
update: "Update"
remove: "Remove"
admin/views/announcements.vue: admin/views/announcements.vue:
announcements: "Announcements" announcements: "Announcements"
save: "Save" save: "Save"

View File

@@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
aliases-desc: "スペースで区切って複数設定できます。" aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL" url: "絵文字画像URL"
add: "追加" add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue: admin/views/announcements.vue:
announcements: "お知らせ" announcements: "お知らせ"
save: "保存" save: "保存"

View File

@@ -445,7 +445,7 @@ common/views/components/profile-editor.vue:
is-cat: "Ce compte est un Chat" is-cat: "Ce compte est un Chat"
is-bot: "Ce compte est un Bot" is-bot: "Ce compte est un Bot"
is-locked: "Demandes dabonnements requièrent lapprobation" is-locked: "Demandes dabonnements requièrent lapprobation"
careful-bot: "Botからのフォローだけ承認制にする" careful-bot: "Les demandes dabonnements venant de Bots requièrent lapprobation"
advanced: "Avancé" advanced: "Avancé"
privacy: "Vie privée" privacy: "Vie privée"
save: "Mettre à jour le profil" save: "Mettre à jour le profil"
@@ -502,7 +502,7 @@ common/views/widgets/tips.vue:
tips-line14: "ホームのカスタマイズ中、ウィジェットを右クリックしてデザインを変更できます" tips-line14: "ホームのカスタマイズ中、ウィジェットを右クリックしてデザインを変更できます"
tips-line17: "Vous pouvez mettre un texte en surbrillance en le mettant entre ** **" tips-line17: "Vous pouvez mettre un texte en surbrillance en le mettant entre ** **"
tips-line19: "Plusieurs fenêtres peuvent être détachées en dehors du navigateur." tips-line19: "Plusieurs fenêtres peuvent être détachées en dehors du navigateur."
tips-line20: "カレンダーウィジェットのパーセンテージは、経過の割合を示しています" tips-line20: "Pourcentage sur le widget calendrier qui indique le pourcentage de temps passé"
tips-line21: "Vous pouvez aussi utiliser l'API pour développer des Bots." tips-line21: "Vous pouvez aussi utiliser l'API pour développer des Bots."
tips-line23: "Mayu est mignone avec ses sourcils." tips-line23: "Mayu est mignone avec ses sourcils."
tips-line24: "Misskey a vu le jour en 2014" tips-line24: "Misskey a vu le jour en 2014"
@@ -549,7 +549,7 @@ desktop/views/components/charts.vue:
drive: "Drive" drive: "Drive"
network: "Réseau" network: "Réseau"
charts: charts:
federation-instances: "インスタンスの増減" federation-instances: "Nombre dinstances : augmentation/diminution"
federation-instances-total: "Nombre total dinstances" federation-instances-total: "Nombre total dinstances"
notes: "投稿の増減 (統合)" notes: "投稿の増減 (統合)"
local-notes: "投稿の増減 (ローカル)" local-notes: "投稿の増減 (ローカル)"
@@ -782,7 +782,7 @@ desktop/views/components/settings.vue:
timeline: "Chronologie" timeline: "Chronologie"
show-my-renotes: "Afficher mes republications dans le fil" show-my-renotes: "Afficher mes republications dans le fil"
show-renoted-my-notes: "Afficher mes republications dans les fils" show-renoted-my-notes: "Afficher mes republications dans les fils"
show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" show-local-renotes: "Afficher les partages locaux sur les fils"
show-maps: "Afficher la carte" show-maps: "Afficher la carte"
deck-column-align: "デッキのカラムの位置" deck-column-align: "デッキのカラムの位置"
deck-column-align-center: "Centrer" deck-column-align-center: "Centrer"
@@ -866,22 +866,22 @@ common/views/components/api-settings.vue:
desktop/views/components/settings.apps.vue: desktop/views/components/settings.apps.vue:
no-apps: "Aucune application autorisée" no-apps: "Aucune application autorisée"
common/views/components/drive-settings.vue: common/views/components/drive-settings.vue:
max: "容量" max: "Maximale"
in-use: "utilisé" in-use: "utilisé"
stats: "Statistiques" stats: "Statistiques"
common/views/components/mute-and-block.vue: common/views/components/mute-and-block.vue:
mute-and-block: "ミュートとブロック" mute-and-block: "Silencer / Bloquer"
mute: "ミュート" mute: "Mettre en sourdine"
block: "ブロック" block: "En cours blocage"
no-muted-users: "ミュートしているユーザーはいません" no-muted-users: "Aucun utilisateur·rice nest mis·e en sourdine"
no-blocked-users: "ブロックしているユーザーはいません" no-blocked-users: "Aucun utilisateur·rice nest bloqué·e"
common/views/components/password-settings.vue: common/views/components/password-settings.vue:
reset: "パスワードを変更する" reset: "Modifier le mot de passe"
enter-current-password: "現在のパスワードを入力してください" enter-current-password: "Entrez votre mot de passe actuel"
enter-new-password: "新しいパスワードを入力してください" enter-new-password: "Saisissez le nouveau mot de passe"
enter-new-password-again: "もう一度新しいパスワードを入力してください" enter-new-password-again: "Entrez à nouveau le nouveau mot de passe"
not-match: "新しいパスワードが一致しません" not-match: "Les nouveaux mots de passe ne sont pas identiques"
changed: "パスワードを変更しました" changed: "Mot de passe modifié avec succès"
desktop/views/components/sub-note-content.vue: desktop/views/components/sub-note-content.vue:
private: "cette publication est privée" private: "cette publication est privée"
deleted: "cette publication a été supprimée" deleted: "cette publication a été supprimée"
@@ -948,82 +948,86 @@ desktop/views/components/window.vue:
popout: "ポップアウト" popout: "ポップアウト"
close: "Fermer" close: "Fermer"
admin/views/index.vue: admin/views/index.vue:
dashboard: "ダッシュボード" dashboard: "Tableau de bord"
instance: "インスタンス" instance: "Instance"
emoji: "カスタム絵文字" emoji: "Emoji"
users: "ユーザー" users: "Utilisateur·rice·s"
update: "更新" update: "Mise à jour"
announcements: "お知らせ" announcements: "Annonces"
hashtags: "ハッシュタグ" hashtags: "Hashtags"
back-to-misskey: "Misskeyに戻る" back-to-misskey: "Retour vers Misskey"
admin/views/dashboard.vue: admin/views/dashboard.vue:
dashboard: "ダッシュボード" dashboard: "Tableau de bord"
accounts: "アカウント" accounts: "Comptes"
notes: "投稿" notes: "Notes"
drive: "ドライブ" drive: "Lecteur"
instances: "インスタンス" instances: "Instances"
this-instance: "このインスタンス" this-instance: "Cette instance"
federated: "連合" federated: "Fédérées"
invite: "招待" invite: "Inviter"
banner-url: "Banner URL" banner-url: "URL de la bannière"
disableRegistration: "Disable new user registration" disableRegistration: "Désactiver lenregistrement de nouveaux utilisateur·rice·s"
disableLocalTimeline: "Disable the local timeline" disableLocalTimeline: "Désactiver le fil local"
admin/views/charts.vue: admin/views/charts.vue:
title: "チャート" title: "Graph"
per-day: "1日ごと" per-day: "par jour"
per-hour: "1時間ごと" per-hour: "par heure"
federation: "フェデレーション" federation: "Fédération"
notes: "投稿" notes: "Publications"
users: "ユーザー" users: "Utilisateur·rice·s"
drive: "ドライブ" drive: "Lecteur"
network: "ネットワーク" network: "Réseau"
charts: charts:
federation-instances: "インスタンスの増減" federation-instances: "Nombre dinstances : augmentation/diminution"
federation-instances-total: "インスタンスの積算" federation-instances-total: "Nombre total dinstances"
notes: "投稿の増減 (統合)" notes: "投稿の増減 (統合)"
local-notes: "投稿の増減 (ローカル)" local-notes: "投稿の増減 (ローカル)"
remote-notes: "投稿の増減 (リモート)" remote-notes: "投稿の増減 (リモート)"
notes-total: "投稿の積算" notes-total: "Total des publications"
users: "ユーザーの増減" users: "Nombre dutilisateur·rice·s : augmentation/diminution"
users-total: "ユーザーの積算" users-total: "Nombre total des utilisateur·rice·s"
drive: "ドライブ使用量の増減" drive: "ドライブ使用量の増減"
drive-total: "ドライブ使用量の積算" drive-total: "Utilisation totale du lecteur"
drive-files: "ドライブのファイル数の増減" drive-files: "ドライブのファイル数の増減"
drive-files-total: "ドライブのファイル数の積算" drive-files-total: "Nombre total de fichiers sur le lecteur"
network-requests: "リクエスト" network-requests: "Requêtes"
network-time: "応答時間" network-time: "Temps de réponse"
network-usage: "通信量" network-usage: "Traffic"
admin/views/users.vue: admin/views/users.vue:
suspend-user: "ユーザーの凍結" suspend-user: "Suspendre un·e utilisateur·rice"
suspend: "凍結" suspend: "Suspendre"
suspended: "凍結しました" suspended: "Suspendu·e avec succès."
unsuspend-user: "ユーザーの凍結の解除" unsuspend-user: "Lever la suspension dutilisateur·rice·s"
unsuspend: "凍結の解除" unsuspend: "Suspension levée"
unsuspended: "凍結を解除しました" unsuspended: "La suspension de lutilisateur·rice a été levée avec succès"
verify-user: "ユーザーの公式アカウント設定" verify-user: "Paramètres de vérification du compte utilisateur"
verify: "公式アカウントにする" verify: "公式アカウントにする"
verified: "公式アカウントにしました" verified: "公式アカウントにしました"
unverify-user: "ユーザーの公式アカウント解除" unverify-user: "ユーザーの公式アカウント解除"
unverify: "公式アカウントを解除する" unverify: "Ôter la vérification du compte"
unverified: "公式アカウントを解除しました" unverified: "Ce compte n'est plus vérifié"
admin/views/emoji.vue: admin/views/emoji.vue:
add-emoji: add-emoji:
title: "絵文字の登録" title: "Ajouter un émoji"
name: "絵文字名" name: "Nom de lémoji"
name-desc: "a~z 0~9 _ の文字が使えます。" name-desc: "a~z 0~9 _ の文字が使えます。"
aliases: "エイリアス" aliases: "Aliases"
aliases-desc: "スペースで区切って複数設定できます。" aliases-desc: "Vous pouvez définir plus dun, séparés par des espaces."
url: "絵文字画像URL" url: "URL de limage"
add: "追加" add: "Ajouter"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue: admin/views/announcements.vue:
announcements: "お知らせ" announcements: "Annonces"
save: "保存" save: "Enregistrer"
remove: "削除" remove: "Supprimer"
add: "追加" add: "Ajouter"
title: "タイトル" title: "Titre"
text: "内容" text: "Contenu"
admin/views/hashtags.vue: admin/views/hashtags.vue:
hided-tags: "Hidden Tags" hided-tags: "Tags cachés"
desktop/views/pages/deck/deck.tl-column.vue: desktop/views/pages/deck/deck.tl-column.vue:
is-media-only: "Les publications médias uniquement" is-media-only: "Les publications médias uniquement"
is-media-view: "Vue média" is-media-view: "Vue média"
@@ -1370,7 +1374,7 @@ mobile/views/pages/settings.vue:
sound: "Sons" sound: "Sons"
enable-sounds: "Activer les sons" enable-sounds: "Activer les sons"
mark-as-read-all-unread-notes: "Marquer toutes les publications comme lues" mark-as-read-all-unread-notes: "Marquer toutes les publications comme lues"
password: "パスワード" password: "Mot de Passe"
mobile/views/pages/user.vue: mobile/views/pages/user.vue:
follows-you: "Vous suit" follows-you: "Vous suit"
following: "Abonnements" following: "Abonnements"

View File

@@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
aliases-desc: "スペースで区切って複数設定できます。" aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL" url: "絵文字画像URL"
add: "追加" add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue: admin/views/announcements.vue:
announcements: "お知らせ" announcements: "お知らせ"
save: "保存" save: "保存"

View File

@@ -131,6 +131,7 @@ common:
show-full-acct: "ユーザー名のホストを省略しない" show-full-acct: "ユーザー名のホストを省略しない"
reduce-motion: "UIの動きを減らす" reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "このデバイスのみ" this-setting-is-this-device-only: "このデバイスのみ"
use-os-default-emojis: "OS標準の絵文字を使用"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。' do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
@@ -417,6 +418,7 @@ common/views/components/signin.vue:
signin: "サインイン" signin: "サインイン"
or: "または" or: "または"
signin-with-twitter: "Twitterでログイン" signin-with-twitter: "Twitterでログイン"
signin-with-github: "GitHubでログイン"
login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。" login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。"
common/views/components/signup.vue: common/views/components/signup.vue:
@@ -460,6 +462,14 @@ common/views/components/twitter-setting.vue:
connect: "Twitterと接続する" connect: "Twitterと接続する"
disconnect: "切断する" disconnect: "切断する"
common/views/components/github-setting.vue:
description: "お使いのGitHubアカウントをお使いのMisskeyアカウントに接続しておくと、プロフィールでGitHubアカウント情報が表示されるようになったり、GitHubを用いた便利なサインインを利用できるようになります。"
connected-to: "次のGitHubアカウントに接続されています"
detail: "詳細..."
reconnect: "再接続する"
connect: "GitHubと接続する"
disconnect: "切断する"
common/views/components/uploader.vue: common/views/components/uploader.vue:
waiting: "待機中" waiting: "待機中"
@@ -599,32 +609,6 @@ desktop/views/components/calendar.vue:
next: "次の月" next: "次の月"
go: "クリックして時間遡行" go: "クリックして時間遡行"
desktop/views/components/charts.vue:
title: "チャート"
per-day: "1日ごと"
per-hour: "1時間ごと"
federation: "フェデレーション"
notes: "投稿"
users: "ユーザー"
drive: "ドライブ"
network: "ネットワーク"
charts:
federation-instances: "インスタンスの増減"
federation-instances-total: "インスタンスの積算"
notes: "投稿の増減 (統合)"
local-notes: "投稿の増減 (ローカル)"
remote-notes: "投稿の増減 (リモート)"
notes-total: "投稿の積算"
users: "ユーザーの増減"
users-total: "ユーザーの積算"
drive: "ドライブ使用量の増減"
drive-total: "ドライブ使用量の積算"
drive-files: "ドライブのファイル数の増減"
drive-files-total: "ドライブのファイル数の積算"
network-requests: "リクエスト"
network-time: "応答時間"
network-usage: "通信量"
desktop/views/components/choose-file-from-drive-window.vue: desktop/views/components/choose-file-from-drive-window.vue:
choose-file: "ファイル選択中" choose-file: "ファイル選択中"
upload: "PCからドライブにファイルをアップロード" upload: "PCからドライブにファイルをアップロード"
@@ -963,6 +947,7 @@ common/views/components/api-settings.vue:
title: 'APIコンソール' title: 'APIコンソール'
endpoint: 'エンドポイント' endpoint: 'エンドポイント'
parameter: 'パラメータ' parameter: 'パラメータ'
credential-info: "「i」パラメータは自動で付与されます。"
send: '送信' send: '送信'
sending: '応答待ち' sending: '応答待ち'
response: '結果' response: '結果'
@@ -1088,10 +1073,24 @@ admin/views/dashboard.vue:
instances: "インスタンス" instances: "インスタンス"
this-instance: "このインスタンス" this-instance: "このインスタンス"
federated: "連合" federated: "連合"
admin/views/instance.vue:
instance: "インスタンス"
instance-name: "インスタンス名"
instance-description: "インスタンスの紹介"
banner-url: "バナー画像URL"
drive-config: "ドライブの設定"
cache-remote-files: "リモートのファイルをキャッシュする"
cache-remote-files-desc: "この設定を無効にすると、リモートファイルをキャッシュせず直リンクするようになります。そのためサーバーのストレージを節約できますが、プライバシー設定で直リンクを無効にしているユーザーにはファイルが見えなくなったり、サムネイルが生成されないので通信量が増加します。通常はこの設定をオンにしておくことをおすすめします。"
local-drive-capacity-mb: "ローカルユーザーひとりあたりのドライブ容量"
remote-drive-capacity-mb: "リモートユーザーひとりあたりのドライブ容量"
mb: "メガバイト単位"
max-note-text-length: "投稿の最大文字数"
disable-registration: "ユーザー登録の受付を停止する"
disable-local-timeline: "ローカルタイムラインを無効にする"
invite: "招待" invite: "招待"
banner-url: "Banner URL" save: "保存"
disableRegistration: "Disable new user registration" saved: "保存しました"
disableLocalTimeline: "Disable the local timeline"
admin/views/charts.vue: admin/views/charts.vue:
title: "チャート" title: "チャート"
@@ -1142,6 +1141,16 @@ admin/views/emoji.vue:
aliases-desc: "スペースで区切って複数設定できます。" aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL" url: "絵文字画像URL"
add: "追加" add: "追加"
info: "50KB以下のPNG画像をおすすめします。"
added: "絵文字を登録しました"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
updated: "更新しました"
remove-emoji:
are-you-sure: "「$1」を削除しますか"
removed: "削除しました"
admin/views/announcements.vue: admin/views/announcements.vue:
announcements: "お知らせ" announcements: "お知らせ"
@@ -1150,6 +1159,10 @@ admin/views/announcements.vue:
add: "追加" add: "追加"
title: "タイトル" title: "タイトル"
text: "内容" text: "内容"
saved: "保存しました"
_remove:
are-you-sure: "「$1」を削除しますか"
removed: "削除しました"
admin/views/hashtags.vue: admin/views/hashtags.vue:
hided-tags: "Hidden Tags" hided-tags: "Hidden Tags"
@@ -1169,12 +1182,6 @@ desktop/views/pages/deck/deck.user-column.vue:
pinned-notes: "ピン留めされた投稿" pinned-notes: "ピン留めされた投稿"
push-to-a-list: "リストに追加" push-to-a-list: "リストに追加"
desktop/views/pages/stats/stats.vue:
all-users: "全てのユーザー"
original-users: "このインスタンスのユーザー"
all-notes: "全ての投稿"
original-notes: "このインスタンスの投稿"
desktop/views/pages/welcome.vue: desktop/views/pages/welcome.vue:
about: "詳しく..." about: "詳しく..."
gotit: "わかった" gotit: "わかった"
@@ -1556,6 +1563,10 @@ mobile/views/pages/settings.vue:
twitter-connect: "Twitterアカウントに接続する" twitter-connect: "Twitterアカウントに接続する"
twitter-reconnect: "再接続する" twitter-reconnect: "再接続する"
twitter-disconnect: "切断する" twitter-disconnect: "切断する"
github: "GitHub連携"
github-connect: "GitHubアカウントに接続する"
github-reconnect: "再接続する"
github-disconnect: "切断する"
update: "Misskey Update" update: "Misskey Update"
version: "バージョン:" version: "バージョン:"
latest-version: "最新のバージョン:" latest-version: "最新のバージョン:"

View File

@@ -186,7 +186,7 @@ common:
stack-left: "左に重ねんで!" stack-left: "左に重ねんで!"
pop-right: "右に出すで!" pop-right: "右に出すで!"
dev: "アプリの作成あかんかったわ。もっぺんやってみて。" dev: "アプリの作成あかんかったわ。もっぺんやってみて。"
ai-chan-kawaii: "藍ちゃかわいい" ai-chan-kawaii: "藍ちゃめっさべっぴんさんや"
auth/views/form.vue: auth/views/form.vue:
share-access: "<i>{{ app.name }}</i>があんさんのアカウントにアクセスすんのを<b>許可</b>してもええか?" share-access: "<i>{{ app.name }}</i>があんさんのアカウントにアクセスすんのを<b>許可</b>してもええか?"
permission-ask: "このアプリは次の権限を要求してんで:" permission-ask: "このアプリは次の権限を要求してんで:"
@@ -744,7 +744,7 @@ desktop/views/components/settings.vue:
apps: "アプリ" apps: "アプリ"
mute-and-block: "ミュート/ブロック" mute-and-block: "ミュート/ブロック"
blocking: "ブロック" blocking: "ブロック"
security: "守護神セキュリティ" security: "セキュリティ"
signin: "こんな感じでサインインしたらしいで" signin: "こんな感じでサインインしたらしいで"
password: "パスワード" password: "パスワード"
2fa: "二段階認証" 2fa: "二段階認証"
@@ -873,15 +873,15 @@ common/views/components/mute-and-block.vue:
mute-and-block: "ミュートとブロック" mute-and-block: "ミュートとブロック"
mute: "ミュート" mute: "ミュート"
block: "ブロック" block: "ブロック"
no-muted-users: "ミュートしているユーザーはいません" no-muted-users: "ミュートしるユーザーはおらんで"
no-blocked-users: "ブロックしているユーザーはいません" no-blocked-users: "ブロックしるユーザーはおらんで"
common/views/components/password-settings.vue: common/views/components/password-settings.vue:
reset: "パスワードを変更する" reset: "パスワード変える"
enter-current-password: "現在のパスワードを入力してください" enter-current-password: "のパスワードを入れてや"
enter-new-password: "新しいパスワードを入力してください" enter-new-password: "こんどのパスワード入れてや"
enter-new-password-again: "もう一度新しいパスワードを入力してください" enter-new-password-again: "もっぺん入れてや"
not-match: "新しいパスワードが一致しません" not-match: "パスワードがおうとらん"
changed: "パスワードを変更しました" changed: "パスワード変えたわ"
desktop/views/components/sub-note-content.vue: desktop/views/components/sub-note-content.vue:
private: "この投稿は見せられへんわ" private: "この投稿は見せられへんわ"
deleted: "この投稿なんか無くなってもうたわ" deleted: "この投稿なんか無くなってもうたわ"
@@ -953,7 +953,7 @@ admin/views/index.vue:
emoji: "カスタム絵文字" emoji: "カスタム絵文字"
users: "ユーザー" users: "ユーザー"
update: "更新" update: "更新"
announcements: "お知らせ" announcements: "知っといてや"
hashtags: "ハッシュタグ" hashtags: "ハッシュタグ"
back-to-misskey: "Misskeyに戻る" back-to-misskey: "Misskeyに戻る"
admin/views/dashboard.vue: admin/views/dashboard.vue:
@@ -962,9 +962,9 @@ admin/views/dashboard.vue:
notes: "投稿" notes: "投稿"
drive: "ドライブ" drive: "ドライブ"
instances: "インスタンス" instances: "インスタンス"
this-instance: "のインスタンス" this-instance: "ワイのインスタンス"
federated: "連合" federated: "連合"
invite: "招待" invite: "来てや"
banner-url: "Banner URL" banner-url: "Banner URL"
disableRegistration: "Disable new user registration" disableRegistration: "Disable new user registration"
disableLocalTimeline: "Disable the local timeline" disableLocalTimeline: "Disable the local timeline"
@@ -980,7 +980,7 @@ admin/views/charts.vue:
charts: charts:
federation-instances: "インスタンスの増減" federation-instances: "インスタンスの増減"
federation-instances-total: "インスタンスの積算" federation-instances-total: "インスタンスの積算"
notes: "投稿の増減 (統合)" notes: "投稿の増減(統合)"
local-notes: "投稿の増減 (ローカル)" local-notes: "投稿の増減 (ローカル)"
remote-notes: "投稿の増減 (リモート)" remote-notes: "投稿の増減 (リモート)"
notes-total: "投稿の積算" notes-total: "投稿の積算"
@@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
aliases-desc: "スペースで区切って複数設定できます。" aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL" url: "絵文字画像URL"
add: "追加" add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue: admin/views/announcements.vue:
announcements: "お知らせ" announcements: "お知らせ"
save: "保存" save: "保存"
@@ -1383,7 +1387,7 @@ mobile/views/pages/user.vue:
mute: "ミュート" mute: "ミュート"
unmute: "ミュート解除" unmute: "ミュート解除"
block: "ブロック" block: "ブロック"
unblock: "ブロック解除" unblock: "ブロックやめたる"
mobile/views/pages/user/home.vue: mobile/views/pages/user/home.vue:
recent-notes: "最近儲かりまっか?" recent-notes: "最近儲かりまっか?"
images: "画像" images: "画像"

View File

@@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
aliases-desc: "スペースで区切って複数設定できます。" aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL" url: "絵文字画像URL"
add: "追加" add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue: admin/views/announcements.vue:
announcements: "お知らせ" announcements: "お知らせ"
save: "保存" save: "保存"

View File

@@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
aliases-desc: "スペースで区切って複数設定できます。" aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL" url: "絵文字画像URL"
add: "追加" add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue: admin/views/announcements.vue:
announcements: "お知らせ" announcements: "お知らせ"
save: "保存" save: "保存"

View File

@@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
aliases-desc: "スペースで区切って複数設定できます。" aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL" url: "絵文字画像URL"
add: "追加" add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue: admin/views/announcements.vue:
announcements: "お知らせ" announcements: "お知らせ"
save: "保存" save: "保存"

View File

@@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
aliases-desc: "スペースで区切って複数設定できます。" aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL" url: "絵文字画像URL"
add: "追加" add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue: admin/views/announcements.vue:
announcements: "お知らせ" announcements: "お知らせ"
save: "保存" save: "保存"

View File

@@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
aliases-desc: "スペースで区切って複数設定できます。" aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL" url: "絵文字画像URL"
add: "追加" add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue: admin/views/announcements.vue:
announcements: "お知らせ" announcements: "お知らせ"
save: "保存" save: "保存"

View File

@@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
aliases-desc: "スペースで区切って複数設定できます。" aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL" url: "絵文字画像URL"
add: "追加" add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue: admin/views/announcements.vue:
announcements: "お知らせ" announcements: "お知らせ"
save: "保存" save: "保存"

View File

@@ -1015,6 +1015,10 @@ admin/views/emoji.vue:
aliases-desc: "スペースで区切って複数設定できます。" aliases-desc: "スペースで区切って複数設定できます。"
url: "絵文字画像URL" url: "絵文字画像URL"
add: "追加" add: "追加"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
admin/views/announcements.vue: admin/views/announcements.vue:
announcements: "お知らせ" announcements: "お知らせ"
save: "保存" save: "保存"

17362
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
{ {
"name": "misskey", "name": "misskey",
"author": "syuilo <i@syuilo.com>", "author": "syuilo <i@syuilo.com>",
"version": "10.38.0", "version": "10.42.2",
"clientVersion": "1.0.11454", "clientVersion": "1.0.11604",
"codename": "nighthike", "codename": "nighthike",
"main": "./built/index.js", "main": "./built/index.js",
"private": true, "private": true,
@@ -20,10 +20,11 @@
"format": "gulp format" "format": "gulp format"
}, },
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-svg-core": "1.2.6", "@fortawesome/fontawesome-svg-core": "1.2.8",
"@fortawesome/free-brands-svg-icons": "5.4.1", "@fortawesome/free-brands-svg-icons": "5.5.0",
"@fortawesome/free-regular-svg-icons": "5.4.1", "@fortawesome/free-regular-svg-icons": "5.5.0",
"@fortawesome/free-solid-svg-icons": "5.4.1", "@fortawesome/free-solid-svg-icons": "5.5.0",
"@fortawesome/vue-fontawesome": "0.1.2",
"@koa/cors": "2.2.2", "@koa/cors": "2.2.2",
"@prezzemolo/rap": "0.1.2", "@prezzemolo/rap": "0.1.2",
"@prezzemolo/zip": "0.0.3", "@prezzemolo/zip": "0.0.3",
@@ -62,6 +63,7 @@
"@types/mongodb": "3.1.12", "@types/mongodb": "3.1.12",
"@types/ms": "0.7.30", "@types/ms": "0.7.30",
"@types/node": "10.12.2", "@types/node": "10.12.2",
"@types/oauth": "0.9.1",
"@types/portscanner": "2.1.0", "@types/portscanner": "2.1.0",
"@types/pug": "2.0.4", "@types/pug": "2.0.4",
"@types/qrcode": "1.3.0", "@types/qrcode": "1.3.0",
@@ -95,7 +97,6 @@
"chai": "4.2.0", "chai": "4.2.0",
"chai-http": "4.2.0", "chai-http": "4.2.0",
"chalk": "2.4.1", "chalk": "2.4.1",
"chart.js": "2.7.3",
"commander": "2.19.0", "commander": "2.19.0",
"crc-32": "1.2.0", "crc-32": "1.2.0",
"css-loader": "1.0.1", "css-loader": "1.0.1",
@@ -112,7 +113,7 @@
"eslint-plugin-vue": "4.7.1", "eslint-plugin-vue": "4.7.1",
"eventemitter3": "3.1.0", "eventemitter3": "3.1.0",
"file-loader": "2.0.0", "file-loader": "2.0.0",
"file-type": "10.3.0", "file-type": "10.4.0",
"fuckadblock": "3.2.1", "fuckadblock": "3.2.1",
"gulp": "3.9.1", "gulp": "3.9.1",
"gulp-cssnano": "2.1.3", "gulp-cssnano": "2.1.3",
@@ -211,12 +212,10 @@
"uuid": "3.3.2", "uuid": "3.3.2",
"v-animate-css": "0.0.2", "v-animate-css": "0.0.2",
"vue": "2.5.17", "vue": "2.5.17",
"vue-chartjs": "3.4.0",
"vue-color": "2.7.0", "vue-color": "2.7.0",
"vue-content-loading": "1.5.3", "vue-content-loading": "1.5.3",
"vue-cropperjs": "2.2.2", "vue-cropperjs": "2.2.2",
"vue-js-modal": "1.3.26", "vue-js-modal": "1.3.26",
"vue-json-tree-view": "2.1.4",
"vue-loader": "15.4.2", "vue-loader": "15.4.2",
"vue-router": "3.0.1", "vue-router": "3.0.1",
"vue-style-loader": "4.1.2", "vue-style-loader": "4.1.2",
@@ -229,7 +228,7 @@
"vuex-persistedstate": "2.5.4", "vuex-persistedstate": "2.5.4",
"web-push": "3.3.3", "web-push": "3.3.3",
"webfinger.js": "2.6.6", "webfinger.js": "2.6.6",
"webpack": "4.23.1", "webpack": "4.25.1",
"webpack-cli": "3.1.2", "webpack-cli": "3.1.2",
"websocket": "1.0.28", "websocket": "1.0.28",
"ws": "6.1.0", "ws": "6.1.0",

View File

@@ -1,7 +1,7 @@
<template> <template>
<div> <div class="cdeuzmsthagexbkpofbmatmugjuvogfb">
<ui-card> <ui-card>
<div slot="title">%fa:broadcast-tower% %i18n:@announcements%</div> <div slot="title"><fa icon="broadcast-tower"/> %i18n:@announcements%</div>
<section v-for="(announcement, i) in announcements" class="fit-top"> <section v-for="(announcement, i) in announcements" class="fit-top">
<ui-input v-model="announcement.title" @change="save"> <ui-input v-model="announcement.title" @change="save">
<span>%i18n:@title%</span> <span>%i18n:@title%</span>
@@ -9,13 +9,13 @@
<ui-textarea v-model="announcement.text"> <ui-textarea v-model="announcement.text">
<span>%i18n:@text%</span> <span>%i18n:@text%</span>
</ui-textarea> </ui-textarea>
<ui-button-group> <ui-horizon-group>
<ui-button inline @click="save">%fa:save R% %i18n:@save%</ui-button> <ui-button @click="save()"><fa :icon="['far', 'save']"/> %i18n:@save%</ui-button>
<ui-button inline @click="remove(i)">%fa:trash-alt R% %i18n:@remove%</ui-button> <ui-button @click="remove(i)"><fa :icon="['far', 'trash-alt']"/> %i18n:@remove%</ui-button>
</ui-button-group> </ui-horizon-group>
</section> </section>
<section> <section>
<ui-button @click="add">%fa:plus% %i18n:@add%</ui-button> <ui-button @click="add"><fa icon="plus"/> %i18n:@add%</ui-button>
</section> </section>
</ui-card> </ui-card>
</div> </div>
@@ -46,19 +46,45 @@ export default Vue.extend({
}, },
remove(i) { remove(i) {
this.announcements = this.announcements.filter((_, j) => j !== i); this.$swal({
this.save(); type: 'warning',
text: '%i18n:@_remove.are-you-sure%'.replace('$1', this.announcements.find((_, j) => j == i).title),
showCancelButton: true
}).then(res => {
if (!res.value) return;
this.announcements = this.announcements.filter((_, j) => j !== i);
this.save(true);
this.$swal({
type: 'success',
text: '%i18n:@_remove.removed%'
});
});
}, },
save() { save(silent) {
(this as any).api('admin/update-meta', { (this as any).api('admin/update-meta', {
broadcasts: this.announcements broadcasts: this.announcements
}).then(() => { }).then(() => {
(this as any).os.apis.dialog({ text: `Saved` }); if (!silent) {
this.$swal({
type: 'success',
text: '%i18n:@saved%'
});
}
}).catch(e => { }).catch(e => {
(this as any).os.apis.dialog({ text: `Failed ${e}` }); this.$swal({
type: 'error',
text: e
});
}); });
} }
} }
}); });
</script> </script>
<style lang="stylus" scoped>
.cdeuzmsthagexbkpofbmatmugjuvogfb
@media (min-width 500px)
padding 16px
</style>

View File

@@ -3,10 +3,10 @@
<table> <table>
<thead> <thead>
<tr> <tr>
<th>%fa:exchange-alt% In/Out</th> <th><fa icon="exchange-alt"/> In/Out</th>
<th>%fa:server% Host</th> <th><fa icon="server"/> Host</th>
<th>%fa:bolt% Activity</th> <th><fa icon="bolt"/> Activity</th>
<th>%fa:user% Actor</th> <th><fa icon="user"/> Actor</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -34,8 +34,8 @@ export default Vue.extend({
mounted() { mounted() {
this.connection = (this as any).os.stream.useSharedConnection('apLog'); this.connection = (this as any).os.stream.useSharedConnection('apLog');
this.connection.on('stats', this.onLog); this.connection.on('log', this.onLog);
this.connection.on('statsLog', this.onLogs); this.connection.on('logs', this.onLogs);
this.connection.send('requestLog', { this.connection.send('requestLog', {
id: Math.random().toString().substr(2, 8), id: Math.random().toString().substr(2, 8),
length: 50 length: 50
@@ -63,11 +63,11 @@ export default Vue.extend({
<style lang="stylus" scoped> <style lang="stylus" scoped>
.hyhctythnmwihguaaapnbrbszsjqxpio .hyhctythnmwihguaaapnbrbszsjqxpio
display block display block
padding 16px padding 12px 16px 16px 16px
height 250px height 250px
overflow auto overflow hidden
box-shadow 0 2px 4px rgba(0, 0, 0, 0.1) box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
background var(--face) background var(--adminDashboardCardBg)
border-radius 8px border-radius 8px
> table > table
@@ -76,10 +76,11 @@ export default Vue.extend({
overflow auto overflow auto
border-spacing 0 border-spacing 0
border-collapse collapse border-collapse collapse
color #555 color var(--adminDashboardCardFg)
font-size 14px
thead thead
border-bottom solid 2px #eee border-bottom solid 1px var(--adminDashboardCardDivider)
tr tr
th th
@@ -89,7 +90,7 @@ export default Vue.extend({
tbody tbody
tr tr
&:nth-child(odd) &:nth-child(odd)
background #fbfbfb background rgba(0, 0, 0, 0.025)
th, td th, td
padding 8px 16px padding 8px 16px

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="qvgidhudpqhjttdhxubzuyrhyzgslujw"> <div class="qvgidhudpqhjttdhxubzuyrhyzgslujw">
<header> <header>
<b>%fa:chart-bar R% %i18n:@title%:</b> <b><fa :icon="['far', 'chart-bar']"/> %i18n:@title%:</b>
<select v-model="src"> <select v-model="src">
<optgroup label="%i18n:@federation%"> <optgroup label="%i18n:@federation%">
<option value="federation-instances">%i18n:@charts.federation-instances%</option> <option value="federation-instances">%i18n:@charts.federation-instances%</option>
@@ -39,6 +39,7 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import * as tinycolor from 'tinycolor2';
import * as ApexCharts from 'apexcharts'; import * as ApexCharts from 'apexcharts';
const limit = 90; const limit = 90;
@@ -147,7 +148,7 @@ export default Vue.extend({
this.chartInstance.destroy(); this.chartInstance.destroy();
} }
this.chartInstance = new ApexCharts(this.$refs.chart, Object.assign({ this.chartInstance = new ApexCharts(this.$refs.chart, {
chart: { chart: {
type: 'area', type: 'area',
height: 300, height: 300,
@@ -168,17 +169,41 @@ export default Vue.extend({
}, },
grid: { grid: {
clipMarkers: false, clipMarkers: false,
borderColor: 'rgba(0, 0, 0, 0.1)'
}, },
stroke: { stroke: {
curve: 'straight', curve: 'straight',
width: 2 width: 2
}, },
legend: {
labels: {
color: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--text')).toRgbString()
},
},
xaxis: { xaxis: {
type: 'datetime' type: 'datetime',
labels: {
style: {
colors: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--text')).toRgbString()
}
},
axisBorder: {
color: 'rgba(0, 0, 0, 0.1)'
},
axisTicks: {
color: 'rgba(0, 0, 0, 0.1)'
},
}, },
yaxis: { yaxis: {
} labels: {
}, this.data)); formatter: this.data.bytes ? v => Vue.filter('bytes')(v, 0) : v => Vue.filter('number')(v),
style: {
color: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--text')).toRgbString()
}
}
},
series: this.data.series
});
this.chartInstance.render(); this.chartInstance.render();
}, },
@@ -249,12 +274,15 @@ export default Vue.extend({
return { return {
series: [{ series: [{
name: 'Combined', name: 'Combined',
type: 'line',
data: this.format(sum(this.stats.notes.local.total, this.stats.notes.remote.total)) data: this.format(sum(this.stats.notes.local.total, this.stats.notes.remote.total))
}, { }, {
name: 'Local', name: 'Local',
type: 'area',
data: this.format(this.stats.notes.local.total) data: this.format(this.stats.notes.local.total)
}, { }, {
name: 'Remote', name: 'Remote',
type: 'area',
data: this.format(this.stats.notes.remote.total) data: this.format(this.stats.notes.remote.total)
}] }]
}; };
@@ -264,18 +292,21 @@ export default Vue.extend({
return { return {
series: [{ series: [{
name: 'Combined', name: 'Combined',
type: 'line',
data: this.format(total data: this.format(total
? sum(this.stats.users.local.total, this.stats.users.remote.total) ? sum(this.stats.users.local.total, this.stats.users.remote.total)
: sum(this.stats.users.local.inc, negate(this.stats.users.local.dec), this.stats.users.remote.inc, negate(this.stats.users.remote.dec)) : sum(this.stats.users.local.inc, negate(this.stats.users.local.dec), this.stats.users.remote.inc, negate(this.stats.users.remote.dec))
) )
}, { }, {
name: 'Local', name: 'Local',
type: 'area',
data: this.format(total data: this.format(total
? this.stats.users.local.total ? this.stats.users.local.total
: sum(this.stats.users.local.inc, negate(this.stats.users.local.dec)) : sum(this.stats.users.local.inc, negate(this.stats.users.local.dec))
) )
}, { }, {
name: 'Remote', name: 'Remote',
type: 'area',
data: this.format(total data: this.format(total
? this.stats.users.remote.total ? this.stats.users.remote.total
: sum(this.stats.users.remote.inc, negate(this.stats.users.remote.dec)) : sum(this.stats.users.remote.inc, negate(this.stats.users.remote.dec))
@@ -286,8 +317,10 @@ export default Vue.extend({
driveChart(): any { driveChart(): any {
return { return {
bytes: true,
series: [{ series: [{
name: 'All', name: 'All',
type: 'line',
data: this.format( data: this.format(
sum( sum(
this.stats.drive.local.incSize, this.stats.drive.local.incSize,
@@ -298,15 +331,19 @@ export default Vue.extend({
) )
}, { }, {
name: 'Local +', name: 'Local +',
type: 'area',
data: this.format(this.stats.drive.local.incSize) data: this.format(this.stats.drive.local.incSize)
}, { }, {
name: 'Local -', name: 'Local -',
type: 'area',
data: this.format(negate(this.stats.drive.local.decSize)) data: this.format(negate(this.stats.drive.local.decSize))
}, { }, {
name: 'Remote +', name: 'Remote +',
type: 'area',
data: this.format(this.stats.drive.remote.incSize) data: this.format(this.stats.drive.remote.incSize)
}, { }, {
name: 'Remote -', name: 'Remote -',
type: 'area',
data: this.format(negate(this.stats.drive.remote.decSize)) data: this.format(negate(this.stats.drive.remote.decSize))
}] }]
}; };
@@ -314,14 +351,18 @@ export default Vue.extend({
driveTotalChart(): any { driveTotalChart(): any {
return { return {
bytes: true,
series: [{ series: [{
name: 'Combined', name: 'Combined',
type: 'line',
data: this.format(sum(this.stats.drive.local.totalSize, this.stats.drive.remote.totalSize)) data: this.format(sum(this.stats.drive.local.totalSize, this.stats.drive.remote.totalSize))
}, { }, {
name: 'Local', name: 'Local',
type: 'area',
data: this.format(this.stats.drive.local.totalSize) data: this.format(this.stats.drive.local.totalSize)
}, { }, {
name: 'Remote', name: 'Remote',
type: 'area',
data: this.format(this.stats.drive.remote.totalSize) data: this.format(this.stats.drive.remote.totalSize)
}] }]
}; };
@@ -331,6 +372,7 @@ export default Vue.extend({
return { return {
series: [{ series: [{
name: 'All', name: 'All',
type: 'line',
data: this.format( data: this.format(
sum( sum(
this.stats.drive.local.incCount, this.stats.drive.local.incCount,
@@ -341,15 +383,19 @@ export default Vue.extend({
) )
}, { }, {
name: 'Local +', name: 'Local +',
type: 'area',
data: this.format(this.stats.drive.local.incCount) data: this.format(this.stats.drive.local.incCount)
}, { }, {
name: 'Local -', name: 'Local -',
type: 'area',
data: this.format(negate(this.stats.drive.local.decCount)) data: this.format(negate(this.stats.drive.local.decCount))
}, { }, {
name: 'Remote +', name: 'Remote +',
type: 'area',
data: this.format(this.stats.drive.remote.incCount) data: this.format(this.stats.drive.remote.incCount)
}, { }, {
name: 'Remote -', name: 'Remote -',
type: 'area',
data: this.format(negate(this.stats.drive.remote.decCount)) data: this.format(negate(this.stats.drive.remote.decCount))
}] }]
}; };
@@ -359,12 +405,15 @@ export default Vue.extend({
return { return {
series: [{ series: [{
name: 'Combined', name: 'Combined',
type: 'line',
data: this.format(sum(this.stats.drive.local.totalCount, this.stats.drive.remote.totalCount)) data: this.format(sum(this.stats.drive.local.totalCount, this.stats.drive.remote.totalCount))
}, { }, {
name: 'Local', name: 'Local',
type: 'area',
data: this.format(this.stats.drive.local.totalCount) data: this.format(this.stats.drive.local.totalCount)
}, { }, {
name: 'Remote', name: 'Remote',
type: 'area',
data: this.format(this.stats.drive.remote.totalCount) data: this.format(this.stats.drive.remote.totalCount)
}] }]
}; };
@@ -396,6 +445,7 @@ export default Vue.extend({
networkUsageChart(): any { networkUsageChart(): any {
return { return {
bytes: true,
series: [{ series: [{
name: 'Incoming', name: 'Incoming',
data: this.format(this.stats.network.incomingBytes) data: this.format(this.stats.network.incomingBytes)
@@ -424,8 +474,8 @@ export default Vue.extend({
margin 0 8px margin 0 8px
padding 0 0 8px 0 padding 0 0 8px 0
font-size 1em font-size 1em
color #555 color var(--adminDashboardCardFg)
border-bottom solid 1px #eee border-bottom solid 1px var(--adminDashboardCardDivider)
> b > b
margin-right 8px margin-right 8px

View File

@@ -2,14 +2,14 @@
<div class="zyknedwtlthezamcjlolyusmipqmjgxz"> <div class="zyknedwtlthezamcjlolyusmipqmjgxz">
<div> <div>
<header> <header>
<span>%fa:microchip% CPU <span>{{ cpuP }}%</span></span> <span><fa icon="microchip"/> CPU <span>{{ cpuP }}%</span></span>
<span v-if="meta">{{ meta.cpu.model }}</span> <span v-if="meta">{{ meta.cpu.model }}</span>
</header> </header>
<div ref="cpu"></div> <div ref="cpu"></div>
</div> </div>
<div> <div>
<header> <header>
<span>%fa:memory% MEM <span>{{ memP }}%</span></span> <span><fa icon="memory"/> MEM <span>{{ memP }}%</span></span>
<span v-if="meta"></span> <span v-if="meta"></span>
</header> </header>
<div ref="mem"></div> <div ref="mem"></div>
@@ -79,6 +79,7 @@ export default Vue.extend({
}, },
grid: { grid: {
clipMarkers: false, clipMarkers: false,
borderColor: 'rgba(0, 0, 0, 0.1)'
}, },
stroke: { stroke: {
curve: 'straight', curve: 'straight',
@@ -153,7 +154,7 @@ export default Vue.extend({
display flex display flex
padding 0 8px padding 0 8px
margin-bottom -16px margin-bottom -16px
color #555 color var(--adminDashboardCardFg)
font-size 14px font-size 14px
> span > span
@@ -167,4 +168,13 @@ export default Vue.extend({
> div > div
margin-bottom -10px margin-bottom -10px
@media (max-width 1000px)
display block
margin-bottom 26px
> div
&:first-child
margin-right 0
margin-bottom 26px
</style> </style>

View File

@@ -11,54 +11,54 @@
<div v-if="stats" class="stats"> <div v-if="stats" class="stats">
<div> <div>
<div> <div>
<div>%fa:user%</div> <div><fa icon="user"/></div>
<div> <div>
<span>%i18n:@accounts%</span> <span>%i18n:@accounts%</span>
<b class="primary">{{ stats.originalUsersCount | number }}</b> <b class="primary">{{ stats.originalUsersCount | number }}</b>
</div> </div>
</div> </div>
<div> <div>
<span>%fa:home% %i18n:@this-instance%</span> <span><fa icon="home"/> %i18n:@this-instance%</span>
<span @click="setChartSrc('users')">%fa:chart-bar R%</span> <span @click="setChartSrc('users')"><fa :icon="['far', 'chart-bar']"/></span>
</div> </div>
</div> </div>
<div> <div>
<div> <div>
<div>%fa:pencil-alt%</div> <div><fa icon="pencil-alt"/></div>
<div> <div>
<span>%i18n:@notes%</span> <span>%i18n:@notes%</span>
<b class="primary">{{ stats.originalNotesCount | number }}</b> <b class="primary">{{ stats.originalNotesCount | number }}</b>
</div> </div>
</div> </div>
<div> <div>
<span>%fa:home% %i18n:@this-instance%</span> <span><fa icon="home"/> %i18n:@this-instance%</span>
<span @click="setChartSrc('notes')">%fa:chart-bar R%</span> <span @click="setChartSrc('notes')"><fa :icon="['far', 'chart-bar']"/></span>
</div> </div>
</div> </div>
<div> <div>
<div> <div>
<div>%fa:database%</div> <div><fa icon="database"/></div>
<div> <div>
<span>%i18n:@drive%</span> <span>%i18n:@drive%</span>
<b>{{ stats.driveUsageLocal | bytes }}</b> <b>{{ stats.driveUsageLocal | bytes }}</b>
</div> </div>
</div> </div>
<div> <div>
<span>%fa:home% %i18n:@this-instance%</span> <span><fa icon="home"/> %i18n:@this-instance%</span>
<span @click="setChartSrc('drive')">%fa:chart-bar R%</span> <span @click="setChartSrc('drive')"><fa :icon="['far', 'chart-bar']"/></span>
</div> </div>
</div> </div>
<div> <div>
<div> <div>
<div>%fa:hdd R%</div> <div><fa :icon="['far', 'hdd']"/></div>
<div> <div>
<span>%i18n:@instances%</span> <span>%i18n:@instances%</span>
<b>{{ stats.instances | number }}</b> <b>{{ stats.instances | number }}</b>
</div> </div>
</div> </div>
<div> <div>
<span>%fa:globe% %i18n:@federated%</span> <span><fa icon="globe"/> %i18n:@federated%</span>
<span @click="setChartSrc('federation-instances-total')">%fa:chart-bar R%</span> <span @click="setChartSrc('federation-instances-total')"><fa :icon="['far', 'chart-bar']"/></span>
</div> </div>
</div> </div>
</div> </div>
@@ -124,17 +124,28 @@ export default Vue.extend({
<style lang="stylus" scoped> <style lang="stylus" scoped>
.obdskegsannmntldydackcpzezagxqfy .obdskegsannmntldydackcpzezagxqfy
padding 16px
@media (min-width 500px)
padding 32px
> header > header
display flex display flex
margin-bottom 16px margin-bottom 16px
padding-bottom 16px padding-bottom 16px
border-bottom solid 1px #ccc border-bottom solid 1px var(--adminDashboardHeaderBorder)
color #777 color var(--adminDashboardHeaderFg)
font-size 14px font-size 14px
white-space nowrap
@media (max-width 1000px)
display none
> p > p
display inline display block
margin 0 32px 0 0 margin 0 32px 0 0
overflow hidden
text-overflow ellipsis
> b > b
&:after &:after
@@ -152,11 +163,10 @@ export default Vue.extend({
> div > div
flex 1 flex 1
max-width 300px
margin-right 16px margin-right 16px
color var(--text) color var(--adminDashboardCardFg)
box-shadow 0 2px 4px rgba(0, 0, 0, 0.1) box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
background var(--face) background var(--adminDashboardCardBg)
border-radius 8px border-radius 8px
&:last-child &:last-child
@@ -192,7 +202,7 @@ export default Vue.extend({
> div:last-child > div:last-child
display flex display flex
padding 6px 16px padding 6px 16px
border-top solid 1px #eee border-top solid 1px var(--adminDashboardCardDivider)
> span > span
font-size 70% font-size 70%
@@ -202,6 +212,21 @@ export default Vue.extend({
margin-left auto margin-left auto
cursor pointer cursor pointer
@media (max-width 900px)
display grid
grid-template-columns 1fr 1fr
grid-template-rows 1fr 1fr
gap 16px
> div
margin-right 0
@media (max-width 500px)
display block
> div:not(:last-child)
margin-bottom 16px
> .charts > .charts
margin-bottom 16px margin-bottom 16px

View File

@@ -1,22 +1,49 @@
<template> <template>
<div> <div class="tumhkfkmgtvzljezfvmgkeurkfncshbe">
<ui-card> <ui-card>
<div slot="title">%fa:plus% %i18n:@add-emoji.title%</div> <div slot="title"><fa icon="plus"/> %i18n:@add-emoji.title%</div>
<section class="fit-top"> <section class="fit-top">
<ui-input v-model="name"> <ui-horizon-group inputs>
<span>%i18n:@add-emoji.name%</span> <ui-input v-model="name">
<span slot="text">%i18n:@add-emoji.name-desc%</span> <span>%i18n:@add-emoji.name%</span>
</ui-input> <span slot="desc">%i18n:@add-emoji.name-desc%</span>
<ui-input v-model="aliases"> </ui-input>
<span>%i18n:@add-emoji.aliases%</span> <ui-input v-model="aliases">
<span slot="text">%i18n:@add-emoji.aliases-desc%</span> <span>%i18n:@add-emoji.aliases%</span>
</ui-input> <span slot="desc">%i18n:@add-emoji.aliases-desc%</span>
</ui-input>
</ui-horizon-group>
<ui-input v-model="url"> <ui-input v-model="url">
<i slot="icon"><fa icon="link"/></i>
<span>%i18n:@add-emoji.url%</span> <span>%i18n:@add-emoji.url%</span>
</ui-input> </ui-input>
<ui-info>%i18n:@add-emoji.info%</ui-info>
<ui-button @click="add">%i18n:@add-emoji.add%</ui-button> <ui-button @click="add">%i18n:@add-emoji.add%</ui-button>
</section> </section>
</ui-card> </ui-card>
<ui-card>
<div slot="title"><fa :icon="['far', 'grin']"/> %i18n:@emojis.title%</div>
<section v-for="emoji in emojis">
<img :src="emoji.url" :alt="emoji.name" style="width: 64px;"/>
<ui-horizon-group inputs>
<ui-input v-model="emoji.name">
<span>%i18n:@add-emoji.name%</span>
</ui-input>
<ui-input v-model="emoji.aliases">
<span>%i18n:@add-emoji.aliases%</span>
</ui-input>
</ui-horizon-group>
<ui-input v-model="emoji.url">
<i slot="icon"><fa icon="link"/></i>
<span>%i18n:@add-emoji.url%</span>
</ui-input>
<ui-horizon-group>
<ui-button @click="updateEmoji(emoji)"><fa :icon="['far', 'save']"/> %i18n:@emojis.update%</ui-button>
<ui-button @click="removeEmoji(emoji)"><fa :icon="['far', 'trash-alt']"/> %i18n:@emojis.remove%</ui-button>
</ui-horizon-group>
</section>
</ui-card>
</div> </div>
</template> </template>
@@ -29,20 +56,92 @@ export default Vue.extend({
name: '', name: '',
url: '', url: '',
aliases: '', aliases: '',
emojis: []
}; };
}, },
mounted() {
this.fetchEmojis();
},
methods: { methods: {
add() { add() {
(this as any).api('admin/add-emoji', { (this as any).api('admin/emoji/add', {
name: this.name, name: this.name,
url: this.url, url: this.url,
aliases: this.aliases.split(' ') aliases: this.aliases.split(' ').filter(x => x.length > 0)
}).then(() => { }).then(() => {
(this as any).os.apis.dialog({ text: `Added` }); this.$swal({
type: 'success',
text: '%i18n:@add-emoji.added%'
});
this.fetchEmojis();
}).catch(e => { }).catch(e => {
(this as any).os.apis.dialog({ text: `Failed ${e}` }); this.$swal({
type: 'error',
text: e
});
});
},
fetchEmojis() {
(this as any).api('admin/emoji/list').then(emojis => {
emojis.reverse();
emojis.forEach(e => e.aliases = (e.aliases || []).join(' '));
this.emojis = emojis;
});
},
updateEmoji(emoji) {
(this as any).api('admin/emoji/update', {
id: emoji.id,
name: emoji.name,
url: emoji.url,
aliases: emoji.aliases.split(' ').filter(x => x.length > 0)
}).then(() => {
this.$swal({
type: 'success',
text: '%i18n:@updated%'
});
}).catch(e => {
this.$swal({
type: 'error',
text: e
});
});
},
removeEmoji(emoji) {
this.$swal({
type: 'warning',
text: '%i18n:@remove-emoji.are-you-sure%'.replace('$1', emoji.name),
showCancelButton: true
}).then(res => {
if (!res.value) return;
(this as any).api('admin/emoji/remove', {
id: emoji.id
}).then(() => {
this.$swal({
type: 'success',
text: '%i18n:@remove-emoji.removed%'
});
this.fetchEmojis();
}).catch(e => {
this.$swal({
type: 'error',
text: e
});
});
}); });
} }
} }
}); });
</script> </script>
<style lang="stylus" scoped>
.tumhkfkmgtvzljezfvmgkeurkfncshbe
@media (min-width 500px)
padding 16px
</style>

View File

@@ -29,9 +29,9 @@ export default Vue.extend({
(this as any).api('admin/update-meta', { (this as any).api('admin/update-meta', {
hidedTags: this.hidedTags.split('\n') hidedTags: this.hidedTags.split('\n')
}).then(() => { }).then(() => {
(this as any).os.apis.dialog({ text: `Saved` }); //(this as any).os.apis.dialog({ text: `Saved` });
}).catch(e => { }).catch(e => {
(this as any).os.apis.dialog({ text: `Failed ${e}` }); //(this as any).os.apis.dialog({ text: `Failed ${e}` });
}); });
} }
} }

View File

@@ -1,6 +1,15 @@
<template> <template>
<div class="mk-admin"> <div class="mk-admin" :class="{ isMobile }">
<nav> <header v-show="isMobile">
<button class="nav" @click="navOpend = true"><fa icon="bars"/></button>
<span>MisskeyMyAdmin</span>
</header>
<div class="nav-backdrop"
v-if="navOpend && isMobile"
@click="navOpend = false"
@touchstart="navOpend = false"
></div>
<nav v-show="navOpend">
<div class="mi"> <div class="mi">
<img svg-inline src="../assets/header-icon.svg"/> <img svg-inline src="../assets/header-icon.svg"/>
</div> </div>
@@ -9,30 +18,30 @@
<p class="name">{{ $store.state.i | userName }}</p> <p class="name">{{ $store.state.i | userName }}</p>
</div> </div>
<ul> <ul>
<li @click="nav('dashboard')" :class="{ active: page == 'dashboard' }">%fa:home .fw%%i18n:@dashboard%</li> <li @click="nav('dashboard')" :class="{ active: page == 'dashboard' }"><fa icon="home" fixed-width/>%i18n:@dashboard%</li>
<li @click="nav('instance')" :class="{ active: page == 'instance' }">%fa:cog .fw%%i18n:@instance%</li> <li @click="nav('instance')" :class="{ active: page == 'instance' }"><fa icon="cog" fixed-width/>%i18n:@instance%</li>
<li @click="nav('users')" :class="{ active: page == 'users' }">%fa:users .fw%%i18n:@users%</li> <li @click="nav('users')" :class="{ active: page == 'users' }"><fa icon="users" fixed-width/>%i18n:@users%</li>
<li @click="nav('emoji')" :class="{ active: page == 'emoji' }">%fa:grin R .fw%%i18n:@emoji%</li> <li @click="nav('emoji')" :class="{ active: page == 'emoji' }"><fa :icon="['far', 'grin']" fixed-width/>%i18n:@emoji%</li>
<li @click="nav('announcements')" :class="{ active: page == 'announcements' }">%fa:broadcast-tower .fw%%i18n:@announcements%</li> <li @click="nav('announcements')" :class="{ active: page == 'announcements' }"><fa icon="broadcast-tower" fixed-width/>%i18n:@announcements%</li>
<li @click="nav('hashtags')" :class="{ active: page == 'hashtags' }">%fa:hashtag .fw%%i18n:@hashtags%</li> <li @click="nav('hashtags')" :class="{ active: page == 'hashtags' }"><fa icon="hashtag" fixed-width/>%i18n:@hashtags%</li>
<!-- <li @click="nav('drive')" :class="{ active: page == 'drive' }">%fa:cloud .fw%%i18n:common.drive%</li> --> <!-- <li @click="nav('drive')" :class="{ active: page == 'drive' }"><fa icon="cloud" fixed-width/>%i18n:common.drive%</li> -->
<!-- <li @click="nav('update')" :class="{ active: page == 'update' }">%i18n:@update%</li> --> <!-- <li @click="nav('update')" :class="{ active: page == 'update' }">%i18n:@update%</li> -->
</ul> </ul>
<div class="back-to-misskey"> <div class="back-to-misskey">
<a href="/">%fa:arrow-left% %i18n:@back-to-misskey%</a> <a href="/"><fa icon="arrow-left"/> %i18n:@back-to-misskey%</a>
</div> </div>
<div class="version"> <div class="version">
<small>Misskey {{ version }}</small> <small>Misskey {{ version }}</small>
</div> </div>
</nav> </nav>
<main> <main>
<div v-show="page == 'dashboard'"><x-dashboard/></div> <div v-if="page == 'dashboard'"><x-dashboard/></div>
<div v-show="page == 'instance'"><x-instance/></div> <div v-if="page == 'instance'"><x-instance/></div>
<div v-if="page == 'users'"><x-users/></div> <div v-if="page == 'users'"><x-users/></div>
<div v-show="page == 'emoji'"><x-emoji/></div> <div v-if="page == 'emoji'"><x-emoji/></div>
<div v-show="page == 'announcements'"><x-announcements/></div> <div v-if="page == 'announcements'"><x-announcements/></div>
<div v-show="page == 'hashtags'"><x-hashtags/></div> <div v-if="page == 'hashtags'"><x-hashtags/></div>
<div v-if="page == 'drive'"></div> <div v-if="page == 'drive'"></div>
<div v-if="page == 'update'"></div> <div v-if="page == 'update'"></div>
</main> </main>
@@ -49,6 +58,10 @@ import XAnnouncements from "./announcements.vue";
import XHashtags from "./hashtags.vue"; import XHashtags from "./hashtags.vue";
import XUsers from "./users.vue"; import XUsers from "./users.vue";
// Detect the user agent
const ua = navigator.userAgent.toLowerCase();
const isMobile = /mobile|iphone|ipad|android/.test(ua);
export default Vue.extend({ export default Vue.extend({
components: { components: {
XDashboard, XDashboard,
@@ -58,10 +71,15 @@ export default Vue.extend({
XHashtags, XHashtags,
XUsers XUsers
}, },
provide: {
isMobile
},
data() { data() {
return { return {
page: 'dashboard', page: 'dashboard',
version version,
isMobile,
navOpend: !isMobile
}; };
}, },
methods: { methods: {
@@ -74,12 +92,46 @@ export default Vue.extend({
<style lang="stylus"> <style lang="stylus">
.mk-admin .mk-admin
$headerHeight = 48px
display flex display flex
height 100% height 100%
> header
position fixed
top 0
z-index 10000
width 100%
color var(--mobileHeaderFg)
background-color var(--mobileHeaderBg)
box-shadow 0 1px 0 rgba(#000, 0.075)
&, *
user-select none
> span
display block
line-height $headerHeight
text-align center
> .nav
display block
position absolute
top 0
left 0
z-index 10001
padding 0
width $headerHeight
font-size 1.4em
line-height $headerHeight
border-right solid 1px rgba(#000, 0.1)
> [data-icon]
transition all 0.2s ease
> nav > nav
position fixed position fixed
z-index 10000 z-index 20001
top 0 top 0
left 0 left 0
width 250px width 250px
@@ -136,7 +188,7 @@ export default Vue.extend({
&:hover &:hover
color #fff color #fff
> [data-fa] > [data-icon]
margin-right 6px margin-right 6px
> .version > .version
@@ -166,7 +218,7 @@ export default Vue.extend({
&:hover &:hover
color #fff color #fff
> [data-fa] > [data-icon]
margin-right 6px margin-right 6px
&.active &.active
@@ -187,9 +239,22 @@ export default Vue.extend({
border-bottom solid 16px transparent border-bottom solid 16px transparent
border-left solid 16px transparent border-left solid 16px transparent
> .nav-backdrop
position fixed
top 0
left 0
z-index 20000
width 100%
height 100%
background var(--mobileNavBackdrop)
> main > main
width 100% width 100%
padding 32px 32px 32px calc(32px + 250px) padding 0 0 0 250px
max-width 1300px max-width 1300px
&.isMobile
> main
padding $headerHeight 0 0 0
</style> </style>

View File

@@ -1,9 +1,22 @@
<template> <template>
<div> <div class="axbwjelsbymowqjyywpirzhdlszoncqs">
<ui-card> <ui-card>
<div slot="title">%i18n:@banner-url%</div> <div slot="title"><fa icon="cog"/> %i18n:@instance%</div>
<section class="fit-top"> <section class="fit-top fit-bottom">
<ui-input v-model="bannerUrl"/> <ui-input v-model="name">%i18n:@instance-name%</ui-input>
<ui-textarea v-model="description">%i18n:@instance-description%</ui-textarea>
<ui-input v-model="bannerUrl"><i slot="icon"><fa icon="link"/></i>%i18n:@banner-url%</ui-input>
</section>
<section class="fit-top fit-bottom">
<ui-input v-model="maxNoteTextLength">%i18n:@max-note-text-length%</ui-input>
</section>
<section class="fit-bottom">
<header><fa icon="cloud"/> %i18n:@drive-config%</header>
<ui-switch v-model="cacheRemoteFiles">%i18n:@cache-remote-files%<span slot="desc">%i18n:@cache-remote-files-desc%</span></ui-switch>
<ui-input v-model="localDriveCapacityMb">%i18n:@local-drive-capacity-mb%<span slot="desc">%i18n:@mb%</span><span slot="suffix">MB</span></ui-input>
<ui-input v-model="remoteDriveCapacityMb" :disabled="!cacheRemoteFiles">%i18n:@remote-drive-capacity-mb%<span slot="desc">%i18n:@mb%</span><span slot="suffix">MB</span></ui-input>
</section>
<section>
<ui-button @click="updateMeta">%i18n:@save%</ui-button> <ui-button @click="updateMeta">%i18n:@save%</ui-button>
</section> </section>
</ui-card> </ui-card>
@@ -35,28 +48,70 @@ export default Vue.extend({
disableRegistration: false, disableRegistration: false,
disableLocalTimeline: false, disableLocalTimeline: false,
bannerUrl: null, bannerUrl: null,
name: null,
description: null,
cacheRemoteFiles: false,
localDriveCapacityMb: null,
remoteDriveCapacityMb: null,
maxNoteTextLength: null,
inviteCode: null, inviteCode: null,
}; };
}, },
created() {
(this as any).os.getMeta().then(meta => {
this.bannerUrl = meta.bannerUrl;
this.name = meta.name;
this.description = meta.description;
this.cacheRemoteFiles = meta.cacheRemoteFiles;
this.localDriveCapacityMb = meta.driveCapacityPerLocalUserMb;
this.remoteDriveCapacityMb = meta.driveCapacityPerRemoteUserMb;
this.maxNoteTextLength = meta.maxNoteTextLength;
});
},
methods: { methods: {
invite() { invite() {
(this as any).api('admin/invite').then(x => { (this as any).api('admin/invite').then(x => {
this.inviteCode = x.code; this.inviteCode = x.code;
}).catch(e => { }).catch(e => {
(this as any).os.apis.dialog({ text: `Failed ${e}` }); this.$swal({
type: 'error',
text: e
});
}); });
}, },
updateMeta() { updateMeta() {
(this as any).api('admin/update-meta', { (this as any).api('admin/update-meta', {
disableRegistration: this.disableRegistration, disableRegistration: this.disableRegistration,
disableLocalTimeline: this.disableLocalTimeline, disableLocalTimeline: this.disableLocalTimeline,
bannerUrl: this.bannerUrl bannerUrl: this.bannerUrl,
name: this.name,
description: this.description,
cacheRemoteFiles: this.cacheRemoteFiles,
localDriveCapacityMb: parseInt(this.localDriveCapacityMb, 10),
remoteDriveCapacityMb: parseInt(this.remoteDriveCapacityMb, 10),
maxNoteTextLength: parseInt(this.maxNoteTextLength, 10)
}).then(() => { }).then(() => {
(this as any).os.apis.dialog({ text: `Saved` }); this.$swal({
type: 'success',
text: '%i18n:@saved%'
});
}).catch(e => { }).catch(e => {
(this as any).os.apis.dialog({ text: `Failed ${e}` }); this.$swal({
type: 'error',
text: e
});
}); });
} }
} }
}); });
</script> </script>
<style lang="stylus" scoped>
.axbwjelsbymowqjyywpirzhdlszoncqs
@media (min-width 500px)
padding 16px
</style>

View File

@@ -1,5 +1,5 @@
<template> <template>
<div> <div class="ucnffhbtogqgscfmqcymwmmupoknpfsw">
<ui-card> <ui-card>
<div slot="title">%i18n:@verify-user%</div> <div slot="title">%i18n:@verify-user%</div>
<section class="fit-top"> <section class="fit-top">
@@ -67,11 +67,11 @@ export default Vue.extend({
const process = async () => { const process = async () => {
const user = await (this as any).os.api('users/show', parseAcct(this.verifyUsername)); const user = await (this as any).os.api('users/show', parseAcct(this.verifyUsername));
await (this as any).os.api('admin/verify-user', { userId: user.id }); await (this as any).os.api('admin/verify-user', { userId: user.id });
(this as any).os.apis.dialog({ text: '%i18n:@verified%' }); //(this as any).os.apis.dialog({ text: '%i18n:@verified%' });
}; };
await process().catch(e => { await process().catch(e => {
(this as any).os.apis.dialog({ text: `Failed: ${e}` }); //(this as any).os.apis.dialog({ text: `Failed: ${e}` });
}); });
this.verifying = false; this.verifying = false;
@@ -83,11 +83,11 @@ export default Vue.extend({
const process = async () => { const process = async () => {
const user = await (this as any).os.api('users/show', parseAcct(this.unverifyUsername)); const user = await (this as any).os.api('users/show', parseAcct(this.unverifyUsername));
await (this as any).os.api('admin/unverify-user', { userId: user.id }); await (this as any).os.api('admin/unverify-user', { userId: user.id });
(this as any).os.apis.dialog({ text: '%i18n:@unverified%' }); //(this as any).os.apis.dialog({ text: '%i18n:@unverified%' });
}; };
await process().catch(e => { await process().catch(e => {
(this as any).os.apis.dialog({ text: `Failed: ${e}` }); //(this as any).os.apis.dialog({ text: `Failed: ${e}` });
}); });
this.unverifying = false; this.unverifying = false;
@@ -99,11 +99,11 @@ export default Vue.extend({
const process = async () => { const process = async () => {
const user = await (this as any).os.api('users/show', parseAcct(this.suspendUsername)); const user = await (this as any).os.api('users/show', parseAcct(this.suspendUsername));
await (this as any).os.api('admin/suspend-user', { userId: user.id }); await (this as any).os.api('admin/suspend-user', { userId: user.id });
(this as any).os.apis.dialog({ text: '%i18n:@suspended%' }); //(this as any).os.apis.dialog({ text: '%i18n:@suspended%' });
}; };
await process().catch(e => { await process().catch(e => {
(this as any).os.apis.dialog({ text: `Failed: ${e}` }); //(this as any).os.apis.dialog({ text: `Failed: ${e}` });
}); });
this.suspending = false; this.suspending = false;
@@ -115,11 +115,11 @@ export default Vue.extend({
const process = async () => { const process = async () => {
const user = await (this as any).os.api('users/show', parseAcct(this.unsuspendUsername)); const user = await (this as any).os.api('users/show', parseAcct(this.unsuspendUsername));
await (this as any).os.api('admin/unsuspend-user', { userId: user.id }); await (this as any).os.api('admin/unsuspend-user', { userId: user.id });
(this as any).os.apis.dialog({ text: '%i18n:@unsuspended%' }); //(this as any).os.apis.dialog({ text: '%i18n:@unsuspended%' });
}; };
await process().catch(e => { await process().catch(e => {
(this as any).os.apis.dialog({ text: `Failed: ${e}` }); //(this as any).os.apis.dialog({ text: `Failed: ${e}` });
}); });
this.unsuspending = false; this.unsuspending = false;
@@ -127,3 +127,10 @@ export default Vue.extend({
} }
}); });
</script> </script>
<style lang="stylus" scoped>
.ucnffhbtogqgscfmqcymwmmupoknpfsw
@media (min-width 500px)
padding 16px
</style>

View File

@@ -128,7 +128,7 @@ pre
overflow auto overflow auto
tab-size 2 tab-size 2
[data-fa] [data-icon]
display inline-block display inline-block
.swal2-container .swal2-container

View File

@@ -1,6 +1,6 @@
<template> <template>
<ui-card> <ui-card>
<div slot="title">%fa:key% API</div> <div slot="title"><fa icon="key"/> API</div>
<section class="fit-top"> <section class="fit-top">
<ui-input :value="$store.state.i.token" readonly> <ui-input :value="$store.state.i.token" readonly>
@@ -9,20 +9,21 @@
<p>%i18n:@intro%</p> <p>%i18n:@intro%</p>
<ui-info warn>%i18n:@caution%</ui-info> <ui-info warn>%i18n:@caution%</ui-info>
<p>%i18n:@regeneration-of-token%</p> <p>%i18n:@regeneration-of-token%</p>
<ui-button @click="regenerateToken">%fa:sync-alt% %i18n:@regenerate-token%</ui-button> <ui-button @click="regenerateToken"><fa icon="sync-alt"/> %i18n:@regenerate-token%</ui-button>
</section> </section>
<section> <section>
<header>%fa:terminal% %i18n:@console.title%</header> <header><fa icon="terminal"/> %i18n:@console.title%</header>
<ui-input v-model="endpoint"> <ui-input v-model="endpoint">
<span>%i18n:@console.endpoint%</span> <span>%i18n:@console.endpoint%</span>
</ui-input> </ui-input>
<ui-textarea v-model="body"> <ui-textarea v-model="body">
<span>%i18n:@console.parameter% (JSON or JSON5)</span> <span>%i18n:@console.parameter% (JSON or JSON5)</span>
<span slot="desc">%i18n:@console.credential-info%</span>
</ui-textarea> </ui-textarea>
<ui-button @click="send" :disabled="sending"> <ui-button @click="send" :disabled="sending">
<template v-if="sending">%i18n:@console.sending%</template> <template v-if="sending">%i18n:@console.sending%</template>
<template v-else>%fa:paper-plane% %i18n:@console.send%</template> <template v-else><fa icon="paper-plane"/> %i18n:@console.send%</template>
</ui-button> </ui-button>
<ui-textarea v-if="res" v-model="res" readonly tall> <ui-textarea v-if="res" v-model="res" readonly tall>
<span>%i18n:@console.response%</span> <span>%i18n:@console.response%</span>

View File

@@ -14,7 +14,8 @@
</ol> </ol>
<ol class="emojis" ref="suggests" v-if="emojis.length > 0"> <ol class="emojis" ref="suggests" v-if="emojis.length > 0">
<li v-for="emoji in emojis" @click="complete(type, emoji.emoji)" @keydown="onKeydown" tabindex="-1"> <li v-for="emoji in emojis" @click="complete(type, emoji.emoji)" @keydown="onKeydown" tabindex="-1">
<span class="emoji" v-if="emoji.url"><img :src="emoji.url" :alt="emoji.emoji"/></span> <span class="emoji" v-if="emoji.isCustomEmoji"><img :src="emoji.url" :alt="emoji.emoji"/></span>
<span class="emoji" v-else-if="!useOsDefaultEmojis"><img :src="emoji.url" :alt="emoji.emoji"/></span>
<span class="emoji" v-else>{{ emoji.emoji }}</span> <span class="emoji" v-else>{{ emoji.emoji }}</span>
<span class="name" v-html="emoji.name.replace(q, `<b>${q}</b>`)"></span> <span class="name" v-html="emoji.name.replace(q, `<b>${q}</b>`)"></span>
<span class="alias" v-if="emoji.aliasOf">({{ emoji.aliasOf }})</span> <span class="alias" v-if="emoji.aliasOf">({{ emoji.aliasOf }})</span>
@@ -33,16 +34,24 @@ type EmojiDef = {
name: string; name: string;
aliasOf?: string; aliasOf?: string;
url?: string; url?: string;
isCustomEmoji?: boolean;
}; };
const lib = Object.entries(emojilib.lib).filter((x: any) => { const lib = Object.entries(emojilib.lib).filter((x: any) => {
return x[1].category != 'flags'; return x[1].category != 'flags';
}); });
const char2file = (char: string) => {
let codes = [...char].map(x => x.codePointAt(0).toString(16));
if (!codes.includes('200d')) codes = codes.filter(x => x != 'fe0f');
return codes.join('-');
};
const emjdb: EmojiDef[] = lib.map((x: any) => ({ const emjdb: EmojiDef[] = lib.map((x: any) => ({
emoji: x[1].char, emoji: x[1].char,
name: x[0], name: x[0],
aliasOf: null aliasOf: null,
url: `https://twemoji.maxcdn.com/2/svg/${char2file(x[1].char)}.svg`
})); }));
lib.forEach((x: any) => { lib.forEach((x: any) => {
@@ -51,7 +60,8 @@ lib.forEach((x: any) => {
emjdb.push({ emjdb.push({
emoji: x[1].char, emoji: x[1].char,
name: k, name: k,
aliasOf: x[0] aliasOf: x[0],
url: `https://twemoji.maxcdn.com/2/svg/${char2file(x[1].char)}.svg`
}); });
}); });
} }
@@ -77,6 +87,10 @@ export default Vue.extend({
computed: { computed: {
items(): HTMLCollection { items(): HTMLCollection {
return (this.$refs.suggests as Element).children; return (this.$refs.suggests as Element).children;
},
useOsDefaultEmojis(): boolean {
return this.$store.state.device.useOsDefaultEmojis;
} }
}, },
@@ -107,7 +121,8 @@ export default Vue.extend({
emojiDefinitions.push({ emojiDefinitions.push({
name: x.name, name: x.name,
emoji: `:${x.name}:`, emoji: `:${x.name}:`,
url: x.url url: x.url,
isCustomEmoji: true
}); });
if (x.aliases) { if (x.aliases) {
@@ -116,7 +131,8 @@ export default Vue.extend({
name: alias, name: alias,
aliasOf: x.name, aliasOf: x.name,
emoji: `:${x.name}:`, emoji: `:${x.name}:`,
url: x.url url: x.url,
isCustomEmoji: true
}); });
}); });
} }
@@ -205,6 +221,15 @@ export default Vue.extend({
} }
} }
} else if (this.type == 'emoji') { } else if (this.type == 'emoji') {
if (this.q == null || this.q == '') {
this.emojis = this.emojiDb.filter(x => x.isCustomEmoji && !x.aliasOf).sort((a, b) => {
var textA = a.name.toUpperCase();
var textB = b.name.toUpperCase();
return (textA < textB) ? -1 : (textA > textB) ? 1 : 0;
});
return;
}
const matched = []; const matched = [];
const max = 30; const max = 30;

View File

@@ -1,35 +1,35 @@
<template> <template>
<div class="troubleshooter"> <div class="troubleshooter">
<div class="body"> <div class="body">
<h1>%fa:wrench%%i18n:@title%</h1> <h1><fa icon="wrench"/>%i18n:@title%</h1>
<div> <div>
<p :data-wip="network == null"> <p :data-wip="network == null">
<template v-if="network != null"> <template v-if="network != null">
<template v-if="network">%fa:check%</template> <template v-if="network"><fa icon="check"/></template>
<template v-if="!network">%fa:times%</template> <template v-if="!network"><fa icon="times"/></template>
</template> </template>
{{ network == null ? '%i18n:@checking-network%' : '%i18n:@network%' }}<mk-ellipsis v-if="network == null"/> {{ network == null ? '%i18n:@checking-network%' : '%i18n:@network%' }}<mk-ellipsis v-if="network == null"/>
</p> </p>
<p v-if="network == true" :data-wip="internet == null"> <p v-if="network == true" :data-wip="internet == null">
<template v-if="internet != null"> <template v-if="internet != null">
<template v-if="internet">%fa:check%</template> <template v-if="internet"><fa icon="check"/></template>
<template v-if="!internet">%fa:times%</template> <template v-if="!internet"><fa icon="times"/></template>
</template> </template>
{{ internet == null ? '%i18n:@checking-internet%' : '%i18n:@internet%' }}<mk-ellipsis v-if="internet == null"/> {{ internet == null ? '%i18n:@checking-internet%' : '%i18n:@internet%' }}<mk-ellipsis v-if="internet == null"/>
</p> </p>
<p v-if="internet == true" :data-wip="server == null"> <p v-if="internet == true" :data-wip="server == null">
<template v-if="server != null"> <template v-if="server != null">
<template v-if="server">%fa:check%</template> <template v-if="server"><fa icon="check"/></template>
<template v-if="!server">%fa:times%</template> <template v-if="!server"><fa icon="times"/></template>
</template> </template>
{{ server == null ? '%i18n:@checking-server%' : '%i18n:@server%' }}<mk-ellipsis v-if="server == null"/> {{ server == null ? '%i18n:@checking-server%' : '%i18n:@server%' }}<mk-ellipsis v-if="server == null"/>
</p> </p>
</div> </div>
<p v-if="!end">%i18n:@finding%<mk-ellipsis/></p> <p v-if="!end">%i18n:@finding%<mk-ellipsis/></p>
<p v-if="network === false"><b>%fa:exclamation-triangle%%i18n:@no-network%</b><br>%i18n:@no-network-desc%</p> <p v-if="network === false"><b><fa icon="exclamation-triangle"/>%i18n:@no-network%</b><br>%i18n:@no-network-desc%</p>
<p v-if="internet === false"><b>%fa:exclamation-triangle%%i18n:@no-internet%</b><br>%i18n:@no-internet-desc%</p> <p v-if="internet === false"><b><fa icon="exclamation-triangle"/>%i18n:@no-internet%</b><br>%i18n:@no-internet-desc%</p>
<p v-if="server === false"><b>%fa:exclamation-triangle%%i18n:@no-server%</b><br>%i18n:@no-server-desc%</p> <p v-if="server === false"><b><fa icon="exclamation-triangle"/>%i18n:@no-server%</b><br>%i18n:@no-server-desc%</p>
<p v-if="server === true" class="success"><b>%fa:info-circle%%i18n:@success%</b><br>%i18n:@success-desc%</p> <p v-if="server === true" class="success"><b><fa icon="info-circle"/>%i18n:@success%</b><br>%i18n:@success-desc%</p>
</div> </div>
<footer> <footer>
<a href="/assets/flush.html">%i18n:@flush%</a> | <a href="/assets/version.html">%i18n:@set-version%</a> <a href="/assets/flush.html">%i18n:@flush%</a> | <a href="/assets/version.html">%i18n:@set-version%</a>
@@ -100,7 +100,7 @@ export default Vue.extend({
color #444 color #444
border-bottom solid 1px #eee border-bottom solid 1px #eee
> [data-fa] > [data-icon]
margin-right 0.25em margin-right 0.25em
> div > div
@@ -115,7 +115,7 @@ export default Vue.extend({
&[data-wip] &[data-wip]
color #888 color #888
> [data-fa] > [data-icon]
margin-right 0.25em margin-right 0.25em
&.times &.times
@@ -132,7 +132,7 @@ export default Vue.extend({
border-top solid 1px #eee border-top solid 1px #eee
> b > b
> [data-fa] > [data-icon]
margin-right 0.25em margin-right 0.25em
&.success &.success

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="mk-connect-failed"> <div class="mk-connect-failed">
<img src="data:image/jpeg;base64,%base64:/assets/error.jpg%" alt=""/> <img src="https://raw.githubusercontent.com/syuilo/misskey/develop/src/client/assets/error.jpg" alt=""/>
<h1>%i18n:@title%</h1> <h1>%i18n:@title%</h1>
<p class="text"> <p class="text">
<span>{{ '%i18n:@description%'.substr(0, '%i18n:@description%'.indexOf('{')) }}</span> <span>{{ '%i18n:@description%'.substr(0, '%i18n:@description%'.indexOf('{')) }}</span>

View File

@@ -1,6 +1,6 @@
<template> <template>
<ui-card> <ui-card>
<div slot="title">%fa:cloud% %i18n:common.drive%</div> <div slot="title"><fa icon="cloud"/> %i18n:common.drive%</div>
<section v-if="!fetching" class="juakhbxthdewydyreaphkepoxgxvfogn"> <section v-if="!fetching" class="juakhbxthdewydyreaphkepoxgxvfogn">
<div class="meter"><div :style="meterStyle"></div></div> <div class="meter"><div :style="meterStyle"></div></div>

View File

@@ -0,0 +1,85 @@
<template>
<img v-if="customEmoji" class="fvgwvorwhxigeolkkrcderjzcawqrscl custom" :src="url" :alt="alt" :title="alt"/>
<img v-else-if="char && !useOsDefaultEmojis" class="fvgwvorwhxigeolkkrcderjzcawqrscl" :src="url" :alt="alt" :title="alt"/>
<span v-else-if="char && useOsDefaultEmojis">{{ char }}</span>
<span v-else>:{{ name }}:</span>
</template>
<script lang="ts">
import Vue from 'vue';
import { lib } from 'emojilib';
export default Vue.extend({
props: {
name: {
type: String,
required: false
},
emoji: {
type: String,
required: false
},
customEmojis: {
required: false,
default: []
}
},
data() {
return {
url: null,
char: null,
customEmoji: null
}
},
computed: {
alt(): string {
return this.customEmoji ? `:${this.customEmoji.name}:` : this.char;
},
useOsDefaultEmojis(): boolean {
return this.$store.state.device.useOsDefaultEmojis;
}
},
created() {
if (this.name) {
const customEmoji = this.customEmojis.find(x => x.name == this.name);
if (customEmoji) {
this.customEmoji = customEmoji;
this.url = customEmoji.url;
} else {
const emoji = lib[this.name];
if (emoji) {
this.char = emoji.char;
}
}
} else {
this.char = this.emoji;
}
if (this.char) {
let codes = [...this.char].map(x => x.codePointAt(0).toString(16));
if (!codes.includes('200d')) codes = codes.filter(x => x != 'fe0f');
this.url = `https://twemoji.maxcdn.com/2/svg/${codes.join('-')}.svg`;
}
}
});
</script>
<style lang="stylus" scoped>
.fvgwvorwhxigeolkkrcderjzcawqrscl
height 1.25em
vertical-align -0.25em
&.custom
height 2.5em
vertical-align middle
transition transform 0.2s ease
&:hover
transform scale(1.2)
</style>

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="wjqjnyhzogztorhrdgcpqlkxhkmuetgj"> <div class="wjqjnyhzogztorhrdgcpqlkxhkmuetgj">
<p>%fa:exclamation-triangle% %i18n:common.error.title%</p> <p><fa icon="exclamation-triangle"/> %i18n:common.error.title%</p>
<ui-button @click="() => $emit('retry')">%i18n:common.error.retry%</ui-button> <ui-button @click="() => $emit('retry')">%i18n:common.error.retry%</ui-button>
</div> </div>
</template> </template>

View File

@@ -1,6 +1,6 @@
<template> <template>
<span class="mk-file-type-icon"> <span class="mk-file-type-icon">
<template v-if="kind == 'image'">%fa:file-image%</template> <template v-if="kind == 'image'"><fa icon="file-image"/></template>
</span> </span>
</template> </template>

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="xqnhankfuuilcwvhgsopeqncafzsquya"> <div class="xqnhankfuuilcwvhgsopeqncafzsquya">
<button class="go-index" v-if="selfNav" @click="goIndex">%fa:arrow-left%</button> <button class="go-index" v-if="selfNav" @click="goIndex"><fa icon="arrow-left"/></button>
<header><b><router-link :to="blackUser | userPage">{{ blackUser | userName }}</router-link></b>(%i18n:common.reversi.black%) vs <b><router-link :to="whiteUser | userPage">{{ whiteUser | userName }}</router-link></b>(%i18n:common.reversi.white%)</header> <header><b><router-link :to="blackUser | userPage">{{ blackUser | userName }}</router-link></b>(%i18n:common.reversi.black%) vs <b><router-link :to="whiteUser | userPage">{{ whiteUser | userName }}</router-link></b>(%i18n:common.reversi.white%)</header>
<div style="overflow: hidden; line-height: 28px;"> <div style="overflow: hidden; line-height: 28px;">
@@ -51,13 +51,13 @@
<div class="player" v-if="game.isEnded"> <div class="player" v-if="game.isEnded">
<div> <div>
<button @click="logPos = 0" :disabled="logPos == 0">%fa:angle-double-left%</button> <button @click="logPos = 0" :disabled="logPos == 0"><fa icon="angle-double-left"/></button>
<button @click="logPos--" :disabled="logPos == 0">%fa:angle-left%</button> <button @click="logPos--" :disabled="logPos == 0"><fa icon="angle-left"/></button>
</div> </div>
<span>{{ logPos }} / {{ logs.length }}</span> <span>{{ logPos }} / {{ logs.length }}</span>
<div> <div>
<button @click="logPos++" :disabled="logPos == logs.length">%fa:angle-right%</button> <button @click="logPos++" :disabled="logPos == logs.length"><fa icon="angle-right"/></button>
<button @click="logPos = logs.length" :disabled="logPos == logs.length">%fa:angle-double-right%</button> <button @click="logPos = logs.length" :disabled="logPos == logs.length"><fa icon="angle-double-right"/></button>
</div> </div>
</div> </div>

View File

@@ -17,13 +17,13 @@
</header> </header>
<div> <div>
<div class="random" v-if="game.settings.map == null">%fa:dice%</div> <div class="random" v-if="game.settings.map == null"><fa icon="dice"/></div>
<div class="board" v-else :style="{ 'grid-template-rows': `repeat(${ game.settings.map.length }, 1fr)`, 'grid-template-columns': `repeat(${ game.settings.map[0].length }, 1fr)` }"> <div class="board" v-else :style="{ 'grid-template-rows': `repeat(${ game.settings.map.length }, 1fr)`, 'grid-template-columns': `repeat(${ game.settings.map[0].length }, 1fr)` }">
<div v-for="(x, i) in game.settings.map.join('')" <div v-for="(x, i) in game.settings.map.join('')"
:data-none="x == ' '" :data-none="x == ' '"
@click="onPixelClick(i, x)"> @click="onPixelClick(i, x)">
<template v-if="x == 'b'"><template v-if="$store.state.device.darkmode">%fa:circle R%</template><template v-else>%fa:circle%</template></template> <template v-if="x == 'b'"><template v-if="$store.state.device.darkmode"><fa :icon="['far', 'circle']"/></template><template v-else><fa icon="circle"/></template></template>
<template v-if="x == 'w'"><template v-if="$store.state.device.darkmode">%fa:circle%</template><template v-else>%fa:circle R%</template></template> <template v-if="x == 'w'"><template v-if="$store.state.device.darkmode"><fa :icon="['far', 'circle']"/></template><template v-else><fa icon="circle"/></template></template>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,63 @@
<template>
<div class="mk-github-setting">
<p>%i18n:@description%<a :href="`${docsUrl}/link-to-github`" target="_blank">%i18n:@detail%</a></p>
<p class="account" v-if="$store.state.i.github" :title="`GitHub ID: ${$store.state.i.github.id}`">%i18n:@connected-to%: <a :href="`https://github.com/${$store.state.i.github.login}`" target="_blank">@{{ $store.state.i.github.login }}</a></p>
<p>
<a :href="`${apiUrl}/connect/github`" target="_blank" @click.prevent="connect">{{ $store.state.i.github ? '%i18n:@reconnect%' : '%i18n:@connect%' }}</a>
<span v-if="$store.state.i.github"> or </span>
<a :href="`${apiUrl}/disconnect/github`" target="_blank" v-if="$store.state.i.github" @click.prevent="disconnect">%i18n:@disconnect%</a>
</p>
<p class="id" v-if="$store.state.i.github">GitHub ID: {{ $store.state.i.github.id }}</p>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import { apiUrl, docsUrl } from '../../../config';
export default Vue.extend({
data() {
return {
form: null,
apiUrl,
docsUrl
};
},
mounted() {
this.$watch('$store.state.i', () => {
if (this.$store.state.i.github && this.form)
this.form.close();
}, {
deep: true
});
},
methods: {
connect() {
this.form = window.open(apiUrl + '/connect/github',
'github_connect_window',
'height=570, width=520');
},
disconnect() {
window.open(apiUrl + '/disconnect/github',
'github_disconnect_window',
'height=570, width=520');
}
}
});
</script>
<style lang="stylus" scoped>
.mk-github-setting
.account
border solid 1px #e1e8ed
border-radius 4px
padding 16px
a
font-weight bold
color inherit
.id
color #8899a6
</style>

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="mk-google"> <div class="mk-google">
<input type="search" v-model="query" :placeholder="q"> <input type="search" v-model="query" :placeholder="q">
<button @click="search">%fa:search% %i18n:common.search%</button> <button @click="search"><fa icon="search"/> %i18n:common.search%</button>
</div> </div>
</template> </template>

View File

@@ -37,12 +37,13 @@ import messaging from './messaging.vue';
import messagingRoom from './messaging-room.vue'; import messagingRoom from './messaging-room.vue';
import urlPreview from './url-preview.vue'; import urlPreview from './url-preview.vue';
import twitterSetting from './twitter-setting.vue'; import twitterSetting from './twitter-setting.vue';
import githubSetting from './github-setting.vue';
import fileTypeIcon from './file-type-icon.vue'; import fileTypeIcon from './file-type-icon.vue';
import Reversi from './games/reversi/reversi.vue'; import emoji from './emoji.vue';
import welcomeTimeline from './welcome-timeline.vue'; import welcomeTimeline from './welcome-timeline.vue';
import uiInput from './ui/input.vue'; import uiInput from './ui/input.vue';
import uiButton from './ui/button.vue'; import uiButton from './ui/button.vue';
import uiButtonGroup from './ui/button-group.vue'; import uiHorizonGroup from './ui/horizon-group.vue';
import uiCard from './ui/card.vue'; import uiCard from './ui/card.vue';
import uiForm from './ui/form.vue'; import uiForm from './ui/form.vue';
import uiTextarea from './ui/textarea.vue'; import uiTextarea from './ui/textarea.vue';
@@ -90,12 +91,13 @@ Vue.component('mk-messaging', messaging);
Vue.component('mk-messaging-room', messagingRoom); Vue.component('mk-messaging-room', messagingRoom);
Vue.component('mk-url-preview', urlPreview); Vue.component('mk-url-preview', urlPreview);
Vue.component('mk-twitter-setting', twitterSetting); Vue.component('mk-twitter-setting', twitterSetting);
Vue.component('mk-github-setting', githubSetting);
Vue.component('mk-file-type-icon', fileTypeIcon); Vue.component('mk-file-type-icon', fileTypeIcon);
Vue.component('mk-reversi', Reversi); Vue.component('mk-emoji', emoji);
Vue.component('mk-welcome-timeline', welcomeTimeline); Vue.component('mk-welcome-timeline', welcomeTimeline);
Vue.component('ui-input', uiInput); Vue.component('ui-input', uiInput);
Vue.component('ui-button', uiButton); Vue.component('ui-button', uiButton);
Vue.component('ui-button-group', uiButtonGroup); Vue.component('ui-horizon-group', uiHorizonGroup);
Vue.component('ui-card', uiCard); Vue.component('ui-card', uiCard);
Vue.component('ui-form', uiForm); Vue.component('ui-form', uiForm);
Vue.component('ui-textarea', uiTextarea); Vue.component('ui-textarea', uiTextarea);

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="mk-media-banner"> <div class="mk-media-banner">
<div class="sensitive" v-if="media.isSensitive && hide" @click="hide = false"> <div class="sensitive" v-if="media.isSensitive && hide" @click="hide = false">
<span class="icon">%fa:exclamation-triangle%</span> <span class="icon"><fa icon="exclamation-triangle"/></span>
<b>%i18n:@sensitive%</b> <b>%i18n:@sensitive%</b>
<span>%i18n:@click-to-show%</span> <span>%i18n:@click-to-show%</span>
</div> </div>
@@ -18,7 +18,7 @@
:title="media.name" :title="media.name"
:download="media.name" :download="media.name"
> >
<span class="icon">%fa:download%</span> <span class="icon"><fa icon="download"/></span>
<b>{{ media.name }}</b> <b>{{ media.name }}</b>
</a> </a>
</div> </div>

View File

@@ -4,7 +4,9 @@
<div class="popover" :class="{ hukidasi }" ref="popover"> <div class="popover" :class="{ hukidasi }" ref="popover">
<template v-for="item, i in items"> <template v-for="item, i in items">
<div v-if="item === null"></div> <div v-if="item === null"></div>
<button v-if="item" @click="clicked(item.action)" v-html="item.icon ? item.icon + ' ' + item.text : item.text" :tabindex="i"></button> <button v-if="item" @click="clicked(item.action)" :tabindex="i">
<fa v-if="item.icon" :icon="item.icon"/>{{ item.text }}
</button>
</template> </template>
</div> </div>
</div> </div>
@@ -188,6 +190,9 @@ export default Vue.extend({
color var(--primaryForeground) color var(--primaryForeground)
background var(--primaryDarken10) background var(--primaryDarken10)
> [data-icon]
margin-right 4px
> div > div
margin 8px 0 margin 8px 0
height 1px height 1px

View File

@@ -14,13 +14,13 @@
<div class="file" @click="file = null" v-if="file">{{ file.name }}</div> <div class="file" @click="file = null" v-if="file">{{ file.name }}</div>
<mk-uploader ref="uploader" @uploaded="onUploaded"/> <mk-uploader ref="uploader" @uploaded="onUploaded"/>
<button class="send" @click="send" :disabled="!canSend || sending" title="%i18n:@send%"> <button class="send" @click="send" :disabled="!canSend || sending" title="%i18n:@send%">
<template v-if="!sending">%fa:paper-plane%</template><template v-if="sending">%fa:spinner .spin%</template> <template v-if="!sending"><fa icon="paper-plane"/></template><template v-if="sending"><fa icon="spinner .spin"/></template>
</button> </button>
<button class="attach-from-local" @click="chooseFile" title="%i18n:@attach-from-local%"> <button class="attach-from-local" @click="chooseFile" title="%i18n:@attach-from-local%">
%fa:upload% <fa icon="upload"/>
</button> </button>
<button class="attach-from-drive" @click="chooseFileFromDrive" title="%i18n:@attach-from-drive%"> <button class="attach-from-drive" @click="chooseFileFromDrive" title="%i18n:@attach-from-drive%">
%fa:R folder-open% <fa :icon="['far', 'folder-open']"/>
</button> </button>
<input ref="file" type="file" @change="onChangeFile"/> <input ref="file" type="file" @change="onChangeFile"/>
</div> </div>

View File

@@ -24,7 +24,7 @@
<footer> <footer>
<span class="read" v-if="isMe && message.isRead">%i18n:@is-read%</span> <span class="read" v-if="isMe && message.isRead">%i18n:@is-read%</span>
<mk-time :time="message.createdAt"/> <mk-time :time="message.createdAt"/>
<template v-if="message.is_edited">%fa:pencil-alt%</template> <template v-if="message.is_edited"><fa icon="pencil-alt"/></template>
</footer> </footer>
</div> </div>
</div> </div>
@@ -179,7 +179,7 @@ export default Vue.extend({
font-size 10px font-size 10px
color var(--messagingRoomMessageInfo) color var(--messagingRoomMessageInfo)
> [data-fa] > [data-icon]
margin-left 4px margin-left 4px
&:not([data-is-me]) &:not([data-is-me])

View File

@@ -4,11 +4,11 @@
@drop.prevent.stop="onDrop" @drop.prevent.stop="onDrop"
> >
<div class="body"> <div class="body">
<p class="init" v-if="init">%fa:spinner .spin%%i18n:common.loading%</p> <p class="init" v-if="init"><fa icon="spinner .spin"/>%i18n:common.loading%</p>
<p class="empty" v-if="!init && messages.length == 0">%fa:info-circle%%i18n:@empty%</p> <p class="empty" v-if="!init && messages.length == 0"><fa icon="info-circle"/>%i18n:@empty%</p>
<p class="no-history" v-if="!init && messages.length > 0 && !existMoreMessages">%fa:flag%%i18n:@no-history%</p> <p class="no-history" v-if="!init && messages.length > 0 && !existMoreMessages"><fa icon="flag"/>%i18n:@no-history%</p>
<button class="more" :class="{ fetching: fetchingMoreMessages }" v-if="existMoreMessages" @click="fetchMoreMessages" :disabled="fetchingMoreMessages"> <button class="more" :class="{ fetching: fetchingMoreMessages }" v-if="existMoreMessages" @click="fetchMoreMessages" :disabled="fetchingMoreMessages">
<template v-if="fetchingMoreMessages">%fa:spinner .pulse .fw%</template>{{ fetchingMoreMessages ? '%i18n:common.loading%' : '%i18n:@more%' }} <template v-if="fetchingMoreMessages"><fa icon="spinner .pulse" fixed-width/></template>{{ fetchingMoreMessages ? '%i18n:common.loading%' : '%i18n:@more%' }}
</button> </button>
<template v-for="(message, i) in _messages"> <template v-for="(message, i) in _messages">
<x-message :message="message" :key="message.id"/> <x-message :message="message" :key="message.id"/>
@@ -20,7 +20,7 @@
<footer> <footer>
<transition name="fade"> <transition name="fade">
<div class="new-message" v-show="showIndicator"> <div class="new-message" v-show="showIndicator">
<button @click="onIndicatorClick">%fa:arrow-circle-down%%i18n:@new-message%</button> <button @click="onIndicatorClick"><i><fa icon="arrow-circle-down"/></i>%i18n:@new-message%</button>
</div> </div>
</transition> </transition>
<x-form :user="user" ref="form"/> <x-form :user="user" ref="form"/>
@@ -280,7 +280,7 @@ export default Vue.extend({
color var(--messagingRoomInfo) color var(--messagingRoomInfo)
opacity 0.5 opacity 0.5
[data-fa] [data-icon]
margin-right 4px margin-right 4px
> .no-history > .no-history
@@ -292,7 +292,7 @@ export default Vue.extend({
color var(--messagingRoomInfo) color var(--messagingRoomInfo)
opacity 0.5 opacity 0.5
[data-fa] [data-icon]
margin-right 4px margin-right 4px
> .more > .more
@@ -313,7 +313,7 @@ export default Vue.extend({
&.fetching &.fetching
cursor wait cursor wait
> [data-fa] > [data-icon]
margin-right 4px margin-right 4px
> .message > .message
@@ -381,7 +381,7 @@ export default Vue.extend({
&:active &:active
background var(--primaryDarken10) background var(--primaryDarken10)
> [data-fa] > i
position absolute position absolute
top 0 top 0
left 10px left 10px

View File

@@ -2,7 +2,7 @@
<div class="mk-messaging" :data-compact="compact"> <div class="mk-messaging" :data-compact="compact">
<div class="search" v-if="!compact" :style="{ top: headerTop + 'px' }"> <div class="search" v-if="!compact" :style="{ top: headerTop + 'px' }">
<div class="form"> <div class="form">
<label for="search-input">%fa:search%</label> <label for="search-input"><i><fa icon="search"/></i></label>
<input v-model="q" type="search" @input="search" @keydown="onSearchKeydown" placeholder="%i18n:@search-user%"/> <input v-model="q" type="search" @input="search" @keydown="onSearchKeydown" placeholder="%i18n:@search-user%"/>
</div> </div>
<div class="result"> <div class="result">
@@ -45,7 +45,7 @@
</template> </template>
</div> </div>
<p class="no-history" v-if="!fetching && messages.length == 0">%i18n:@no-history%</p> <p class="no-history" v-if="!fetching && messages.length == 0">%i18n:@no-history%</p>
<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p> <p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p>
</div> </div>
</template> </template>
@@ -213,7 +213,7 @@ export default Vue.extend({
width 38px width 38px
pointer-events none pointer-events none
> [data-fa] > i
display block display block
position absolute position absolute
top 0 top 0
@@ -418,7 +418,7 @@ export default Vue.extend({
text-align center text-align center
color #aaa color #aaa
> [data-fa] > [data-icon]
margin-right 4px margin-right 4px
// TODO: element base media query // TODO: element base media query

View File

@@ -1,5 +1,4 @@
import Vue, { VNode } from 'vue'; import Vue, { VNode } from 'vue';
import * as emojilib from 'emojilib';
import { length } from 'stringz'; import { length } from 'stringz';
import parse from '../../../../../mfm/parse'; import parse from '../../../../../mfm/parse';
import getAcct from '../../../../../misc/acct/render'; import getAcct from '../../../../../misc/acct/render';
@@ -188,24 +187,16 @@ export default Vue.component('misskey-flavored-markdown', {
} }
case 'emoji': { case 'emoji': {
//#region カスタム絵文字 const customEmojis = (this.os.getMetaSync() || { emojis: [] }).emojis || [];
if (this.customEmojis != null) { return [createElement('mk-emoji', {
const customEmoji = this.customEmojis.find(e => e.name == token.emoji || (e.aliases || []).includes(token.emoji)); attrs: {
if (customEmoji) { emoji: token.emoji,
return [createElement('img', { name: token.name
attrs: { },
src: customEmoji.url, props: {
alt: token.emoji, customEmojis: this.customEmojis || customEmojis
title: token.emoji,
style: 'height: 2.5em; vertical-align: middle;'
}
})];
} }
} })];
//#endregion
const emoji = emojilib.lib[token.emoji];
return [createElement('span', emoji ? emoji.char : token.content)];
} }
case 'search': { case 'search': {

View File

@@ -1,6 +1,6 @@
<template> <template>
<ui-card> <ui-card>
<div slot="title">%fa:ban% %i18n:@mute-and-block%</div> <div slot="title"><fa icon="ban"/> %i18n:@mute-and-block%</div>
<section> <section>
<header>%i18n:@mute%</header> <header>%i18n:@mute%</header>

View File

@@ -2,15 +2,11 @@
<span class="mk-nav"> <span class="mk-nav">
<a :href="aboutUrl">%i18n:@about%</a> <a :href="aboutUrl">%i18n:@about%</a>
<i></i> <i></i>
<a href="/stats">%i18n:@stats%</a>
<i></i>
<a :href="repositoryUrl">%i18n:@repository%</a> <a :href="repositoryUrl">%i18n:@repository%</a>
<i></i> <i></i>
<a :href="feedbackUrl" target="_blank">%i18n:@feedback%</a> <a :href="feedbackUrl" target="_blank">%i18n:@feedback%</a>
<i></i> <i></i>
<a href="/dev">%i18n:@develop%</a> <a href="/dev">%i18n:@develop%</a>
<i></i>
<a href="https://twitter.com/misskey_xyz" target="_blank">Follow us on %fa:B twitter%</a>
</span> </span>
</template> </template>

View File

@@ -6,18 +6,18 @@
<span class="is-bot" v-if="note.user.isBot">bot</span> <span class="is-bot" v-if="note.user.isBot">bot</span>
<span class="is-cat" v-if="note.user.isCat">cat</span> <span class="is-cat" v-if="note.user.isCat">cat</span>
<span class="username"><mk-acct :user="note.user"/></span> <span class="username"><mk-acct :user="note.user"/></span>
<span class="is-verified" v-if="note.user.isVerified" title="%i18n:common.verified-user%">%fa:star%</span> <span class="is-verified" v-if="note.user.isVerified" title="%i18n:common.verified-user%"><fa icon="star"/></span>
<div class="info"> <div class="info">
<span class="app" v-if="note.app && !mini">via <b>{{ note.app.name }}</b></span> <span class="app" v-if="note.app && !mini">via <b>{{ note.app.name }}</b></span>
<span class="mobile" v-if="note.viaMobile">%fa:mobile-alt%</span> <span class="mobile" v-if="note.viaMobile"><fa icon="mobile-alt"/></span>
<router-link class="created-at" :to="note | notePage"> <router-link class="created-at" :to="note | notePage">
<mk-time :time="note.createdAt"/> <mk-time :time="note.createdAt"/>
</router-link> </router-link>
<span class="visibility" v-if="note.visibility != 'public'"> <span class="visibility" v-if="note.visibility != 'public'">
<template v-if="note.visibility == 'home'">%fa:home%</template> <template v-if="note.visibility == 'home'"><fa icon="home"/></template>
<template v-if="note.visibility == 'followers'">%fa:unlock%</template> <template v-if="note.visibility == 'followers'"><fa icon="unlock"/></template>
<template v-if="note.visibility == 'specified'">%fa:envelope%</template> <template v-if="note.visibility == 'specified'"><fa icon="envelope"/></template>
<template v-if="note.visibility == 'private'">%fa:lock%</template> <template v-if="note.visibility == 'private'"><fa icon="lock"/></template>
</span> </span>
</div> </div>
</header> </header>

View File

@@ -15,18 +15,18 @@ export default Vue.extend({
computed: { computed: {
items() { items() {
const items = [{ const items = [{
icon: '%fa:info-circle%', icon: 'info-circle',
text: '%i18n:@detail%', text: '%i18n:@detail%',
action: this.detail action: this.detail
}, { }, {
icon: '%fa:link%', icon: 'link',
text: '%i18n:@copy-link%', text: '%i18n:@copy-link%',
action: this.copyLink action: this.copyLink
}]; }];
if (this.note.uri) { if (this.note.uri) {
items.push({ items.push({
icon: '%fa:external-link-square-alt%', icon: 'external-link-square-alt',
text: '%i18n:@remote%', text: '%i18n:@remote%',
action: () => { action: () => {
window.open(this.note.uri, '_blank'); window.open(this.note.uri, '_blank');
@@ -38,13 +38,13 @@ export default Vue.extend({
if (this.note.isFavorited) { if (this.note.isFavorited) {
items.push({ items.push({
icon: '%fa:star%', icon: 'star',
text: '%i18n:@unfavorite%', text: '%i18n:@unfavorite%',
action: this.unfavorite action: this.unfavorite
}); });
} else { } else {
items.push({ items.push({
icon: '%fa:star%', icon: 'star',
text: '%i18n:@favorite%', text: '%i18n:@favorite%',
action: this.favorite action: this.favorite
}); });
@@ -53,13 +53,13 @@ export default Vue.extend({
if (this.note.userId == this.$store.state.i.id) { if (this.note.userId == this.$store.state.i.id) {
if ((this.$store.state.i.pinnedNoteIds || []).includes(this.note.id)) { if ((this.$store.state.i.pinnedNoteIds || []).includes(this.note.id)) {
items.push({ items.push({
icon: '%fa:thumbtack%', icon: 'thumbtack',
text: '%i18n:@unpin%', text: '%i18n:@unpin%',
action: this.unpin action: this.unpin
}); });
} else { } else {
items.push({ items.push({
icon: '%fa:thumbtack%', icon: 'thumbtack',
text: '%i18n:@pin%', text: '%i18n:@pin%',
action: this.pin action: this.pin
}); });
@@ -69,7 +69,7 @@ export default Vue.extend({
if (this.note.userId == this.$store.state.i.id || this.$store.state.i.isAdmin) { if (this.note.userId == this.$store.state.i.id || this.$store.state.i.isAdmin) {
items.push(null); items.push(null);
items.push({ items.push({
icon: '%fa:trash-alt R%', icon: ['far', 'trash-alt'],
text: '%i18n:@delete%', text: '%i18n:@delete%',
action: this.del action: this.del
}); });

View File

@@ -1,19 +1,19 @@
<template> <template>
<div class="mk-poll-editor"> <div class="mk-poll-editor">
<p class="caution" v-if="choices.length < 2"> <p class="caution" v-if="choices.length < 2">
%fa:exclamation-triangle%%i18n:@no-only-one-choice% <fa icon="exclamation-triangle"/>%i18n:@no-only-one-choice%
</p> </p>
<ul ref="choices"> <ul ref="choices">
<li v-for="(choice, i) in choices"> <li v-for="(choice, i) in choices">
<input :value="choice" @input="onInput(i, $event)" :placeholder="'%i18n:@choice-n%'.replace('{}', i + 1)"> <input :value="choice" @input="onInput(i, $event)" :placeholder="'%i18n:@choice-n%'.replace('{}', i + 1)">
<button @click="remove(i)" title="%i18n:@remove%"> <button @click="remove(i)" title="%i18n:@remove%">
%fa:times% <fa icon="times"/>
</button> </button>
</li> </li>
</ul> </ul>
<button class="add" v-if="choices.length < 10" @click="add">%i18n:@add%</button> <button class="add" v-if="choices.length < 10" @click="add">%i18n:@add%</button>
<button class="destroy" @click="destroy" title="%i18n:@destroy%"> <button class="destroy" @click="destroy" title="%i18n:@destroy%">
%fa:times% <fa icon="times"/>
</button> </button>
</div> </div>
</template> </template>
@@ -76,7 +76,7 @@ export default Vue.extend({
font-size 0.8em font-size 0.8em
color #f00 color #f00
> [data-fa] > [data-icon]
margin-right 4px margin-right 4px
> ul > ul

View File

@@ -4,7 +4,7 @@
<li v-for="choice in poll.choices" :key="choice.id" @click="vote(choice.id)" :class="{ voted: choice.voted }" :title="!isVoted ? '%i18n:@vote-to%'.replace('{}', choice.text) : ''"> <li v-for="choice in poll.choices" :key="choice.id" @click="vote(choice.id)" :class="{ voted: choice.voted }" :title="!isVoted ? '%i18n:@vote-to%'.replace('{}', choice.text) : ''">
<div class="backdrop" :style="{ 'width': (showResult ? (choice.votes / total * 100) : 0) + '%' }"></div> <div class="backdrop" :style="{ 'width': (showResult ? (choice.votes / total * 100) : 0) + '%' }"></div>
<span> <span>
<template v-if="choice.isVoted">%fa:check%</template> <template v-if="choice.isVoted"><fa icon="check"/></template>
<span>{{ choice.text }}</span> <span>{{ choice.text }}</span>
<span class="votes" v-if="showResult">({{ '%i18n:@vote-count%'.replace('{}', choice.votes) }})</span> <span class="votes" v-if="showResult">({{ '%i18n:@vote-count%'.replace('{}', choice.votes) }})</span>
</span> </span>
@@ -100,7 +100,7 @@ export default Vue.extend({
transition width 1s ease transition width 1s ease
> span > span
> [data-fa] > [data-icon]
margin-right 4px margin-right 4px
> .votes > .votes

View File

@@ -1,6 +1,6 @@
<template> <template>
<ui-card> <ui-card>
<div slot="title">%fa:user% %i18n:@title%</div> <div slot="title"><fa icon="user"/> %i18n:@title%</div>
<section class="fit-top"> <section class="fit-top">
<ui-form :disabled="saving"> <ui-form :disabled="saving">
@@ -16,12 +16,12 @@
<ui-input v-model="location"> <ui-input v-model="location">
<span>%i18n:@location%</span> <span>%i18n:@location%</span>
<span slot="prefix">%fa:map-marker-alt%</span> <span slot="prefix"><fa icon="map-marker-alt"/></span>
</ui-input> </ui-input>
<ui-input v-model="birthday" type="date"> <ui-input v-model="birthday" type="date">
<span>%i18n:@birthday%</span> <span>%i18n:@birthday%</span>
<span slot="prefix">%fa:birthday-cake%</span> <span slot="prefix"><fa icon="birthday-cake"/></span>
</ui-input> </ui-input>
<ui-textarea v-model="description" :max="500"> <ui-textarea v-model="description" :max="500">
@@ -30,14 +30,14 @@
<ui-input type="file" @change="onAvatarChange"> <ui-input type="file" @change="onAvatarChange">
<span>%i18n:@avatar%</span> <span>%i18n:@avatar%</span>
<span slot="icon">%fa:image%</span> <span slot="icon"><fa icon="image"/></span>
<span slot="text" v-if="avatarUploading">%i18n:@uploading%<mk-ellipsis/></span> <span slot="desc" v-if="avatarUploading">%i18n:@uploading%<mk-ellipsis/></span>
</ui-input> </ui-input>
<ui-input type="file" @change="onBannerChange"> <ui-input type="file" @change="onBannerChange">
<span>%i18n:@banner%</span> <span>%i18n:@banner%</span>
<span slot="icon">%fa:image%</span> <span slot="icon"><fa icon="image"/></span>
<span slot="text" v-if="bannerUploading">%i18n:@uploading%<mk-ellipsis/></span> <span slot="desc" v-if="bannerUploading">%i18n:@uploading%<mk-ellipsis/></span>
</ui-input> </ui-input>
<ui-button @click="save(true)">%i18n:@save%</ui-button> <ui-button @click="save(true)">%i18n:@save%</ui-button>

View File

@@ -8,11 +8,12 @@
</ui-input> </ui-input>
<ui-input v-model="password" type="password" required styl="fill"> <ui-input v-model="password" type="password" required styl="fill">
<span>%i18n:@password%</span> <span>%i18n:@password%</span>
<span slot="prefix">%fa:lock%</span> <span slot="prefix"><fa icon="lock"/></span>
</ui-input> </ui-input>
<ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="number" required styl="fill"/> <ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="number" required styl="fill"/>
<ui-button type="submit" :disabled="signing">{{ signing ? '%i18n:@signing-in%' : '%i18n:@signin%' }}</ui-button> <ui-button type="submit" :disabled="signing">{{ signing ? '%i18n:@signing-in%' : '%i18n:@signin%' }}</ui-button>
<p style="margin: 8px 0;">%i18n:@or% <a :href="`${apiUrl}/signin/twitter`">%i18n:@signin-with-twitter%</a></p> <p style="margin: 8px 0;">%i18n:@or% <a :href="`${apiUrl}/signin/twitter`">%i18n:@signin-with-twitter%</a></p>
<p style="margin: 8px 0;">%i18n:@or% <a :href="`${apiUrl}/signin/github`">%i18n:@signin-with-github%</a></p>
</form> </form>
</template> </template>

View File

@@ -3,36 +3,36 @@
<template v-if="meta"> <template v-if="meta">
<ui-input v-if="meta.disableRegistration" v-model="invitationCode" type="text" :autocomplete="Math.random()" spellcheck="false" required styl="fill"> <ui-input v-if="meta.disableRegistration" v-model="invitationCode" type="text" :autocomplete="Math.random()" spellcheck="false" required styl="fill">
<span>%i18n:@invitation-code%</span> <span>%i18n:@invitation-code%</span>
<span slot="prefix">%fa:id-card-alt%</span> <span slot="prefix"><fa icon="id-card-alt"/></span>
<p slot="text" v-html="'%i18n:@invitation-info%'.replace('{}', meta.maintainer.url)"></p> <p slot="desc" v-html="'%i18n:@invitation-info%'.replace('{}', meta.maintainer.url)"></p>
</ui-input> </ui-input>
<ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @input="onChangeUsername" styl="fill"> <ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @input="onChangeUsername" styl="fill">
<span>%i18n:@username%</span> <span>%i18n:@username%</span>
<span slot="prefix">@</span> <span slot="prefix">@</span>
<span slot="suffix">@{{ host }}</span> <span slot="suffix">@{{ host }}</span>
<p slot="text" v-if="usernameState == 'wait'" style="color:#999">%fa:spinner .pulse .fw% %i18n:@checking%</p> <p slot="desc" v-if="usernameState == 'wait'" style="color:#999"><fa icon="spinner .pulse" fixed-width/> %i18n:@checking%</p>
<p slot="text" v-if="usernameState == 'ok'" style="color:#3CB7B5">%fa:check .fw% %i18n:@available%</p> <p slot="desc" v-if="usernameState == 'ok'" style="color:#3CB7B5"><fa icon="check" fixed-width/> %i18n:@available%</p>
<p slot="text" v-if="usernameState == 'unavailable'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@unavailable%</p> <p slot="desc" v-if="usernameState == 'unavailable'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@unavailable%</p>
<p slot="text" v-if="usernameState == 'error'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@error%</p> <p slot="desc" v-if="usernameState == 'error'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@error%</p>
<p slot="text" v-if="usernameState == 'invalid-format'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@invalid-format%</p> <p slot="desc" v-if="usernameState == 'invalid-format'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@invalid-format%</p>
<p slot="text" v-if="usernameState == 'min-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-short%</p> <p slot="desc" v-if="usernameState == 'min-range'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@too-short%</p>
<p slot="text" v-if="usernameState == 'max-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-long%</p> <p slot="desc" v-if="usernameState == 'max-range'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@too-long%</p>
</ui-input> </ui-input>
<ui-input v-model="password" type="password" :autocomplete="Math.random()" required @input="onChangePassword" :with-password-meter="true" styl="fill"> <ui-input v-model="password" type="password" :autocomplete="Math.random()" required @input="onChangePassword" :with-password-meter="true" styl="fill">
<span>%i18n:@password%</span> <span>%i18n:@password%</span>
<span slot="prefix">%fa:lock%</span> <span slot="prefix"><fa icon="lock"/></span>
<div slot="text"> <div slot="desc">
<p slot="text" v-if="passwordStrength == 'low'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@weak-password%</p> <p v-if="passwordStrength == 'low'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@weak-password%</p>
<p slot="text" v-if="passwordStrength == 'medium'" style="color:#3CB7B5">%fa:check .fw% %i18n:@normal-password%</p> <p v-if="passwordStrength == 'medium'" style="color:#3CB7B5"><fa icon="check" fixed-width/> %i18n:@normal-password%</p>
<p slot="text" v-if="passwordStrength == 'high'" style="color:#3CB7B5">%fa:check .fw% %i18n:@strong-password%</p> <p v-if="passwordStrength == 'high'" style="color:#3CB7B5"><fa icon="check" fixed-width/> %i18n:@strong-password%</p>
</div> </div>
</ui-input> </ui-input>
<ui-input v-model="retypedPassword" type="password" :autocomplete="Math.random()" required @input="onChangePasswordRetype" styl="fill"> <ui-input v-model="retypedPassword" type="password" :autocomplete="Math.random()" required @input="onChangePasswordRetype" styl="fill">
<span>%i18n:@password% (%i18n:@retype%)</span> <span>%i18n:@password% (%i18n:@retype%)</span>
<span slot="prefix">%fa:lock%</span> <span slot="prefix"><fa icon="lock"/></span>
<div slot="text"> <div slot="desc">
<p slot="text" v-if="passwordRetypeState == 'match'" style="color:#3CB7B5">%fa:check .fw% %i18n:@password-matched%</p> <p v-if="passwordRetypeState == 'match'" style="color:#3CB7B5"><fa icon="check" fixed-width/> %i18n:@password-matched%</p>
<p slot="text" v-if="passwordRetypeState == 'not-match'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@password-not-matched%</p> <p v-if="passwordRetypeState == 'not-match'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@password-not-matched%</p>
</div> </div>
</ui-input> </ui-input>
<div v-if="meta.recaptchaSitekey != null" class="g-recaptcha" :data-sitekey="meta.recaptchaSitekey" style="margin: 16px 0;"></div> <div v-if="meta.recaptchaSitekey != null" class="g-recaptcha" :data-sitekey="meta.recaptchaSitekey" style="margin: 16px 0;"></div>

View File

@@ -1,15 +1,15 @@
<template> <template>
<div class="mk-stream-indicator"> <div class="mk-stream-indicator">
<p v-if="stream.state == 'initializing'"> <p v-if="stream.state == 'initializing'">
%fa:spinner .pulse% <fa icon="spinner .pulse"/>
<span>%i18n:@connecting%<mk-ellipsis/></span> <span>%i18n:@connecting%<mk-ellipsis/></span>
</p> </p>
<p v-if="stream.state == 'reconnecting'"> <p v-if="stream.state == 'reconnecting'">
%fa:spinner .pulse% <fa icon="spinner .pulse"/>
<span>%i18n:@reconnecting%<mk-ellipsis/></span> <span>%i18n:@reconnecting%<mk-ellipsis/></span>
</p> </p>
<p v-if="stream.state == 'connected'"> <p v-if="stream.state == 'connected'">
%fa:check% <fa icon="check"/>
<span>%i18n:@connected%</span> <span>%i18n:@connected%</span>
</p> </p>
</div> </div>
@@ -80,7 +80,7 @@ export default Vue.extend({
display block display block
margin 0 margin 0
> [data-fa] > [data-icon]
margin-right 0.25em margin-right 0.25em
</style> </style>

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="jtivnzhfwquxpsfidertopbmwmchmnmo"> <div class="jtivnzhfwquxpsfidertopbmwmchmnmo">
<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p> <p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p>
<p class="empty" v-else-if="tags.length == 0">%fa:exclamation-circle%%i18n:@empty%</p> <p class="empty" v-else-if="tags.length == 0"><fa icon="exclamation-circle"/>%i18n:@empty%</p>
<div v-else> <div v-else>
<vue-word-cloud <vue-word-cloud
:words="tags.slice(0, 20).map(x => [x.name, x.count])" :words="tags.slice(0, 20).map(x => [x.name, x.count])"
@@ -74,7 +74,7 @@ export default Vue.extend({
text-align center text-align center
color #aaa color #aaa
> [data-fa] > [data-icon]
margin-right 4px margin-right 4px
> div > div

View File

@@ -25,7 +25,7 @@
</label> </label>
<details class="creator"> <details class="creator">
<summary>%fa:palette% %i18n:@create-a-theme%</summary> <summary><fa icon="palette"/> %i18n:@create-a-theme%</summary>
<div> <div>
<span>%i18n:@base-theme%:</span> <span>%i18n:@base-theme%:</span>
<ui-radio v-model="myThemeBase" value="light">%i18n:@base-theme-light%</ui-radio> <ui-radio v-model="myThemeBase" value="light">%i18n:@base-theme-light%</ui-radio>
@@ -51,23 +51,23 @@
<div style="padding-bottom:8px;">%i18n:@text-color%:</div> <div style="padding-bottom:8px;">%i18n:@text-color%:</div>
<color-picker v-model="myThemeText"/> <color-picker v-model="myThemeText"/>
</div> </div>
<ui-button @click="preview()">%fa:eye% %i18n:@preview-created-theme%</ui-button> <ui-button @click="preview()"><fa icon="eye"/> %i18n:@preview-created-theme%</ui-button>
<ui-button primary @click="gen()">%fa:save R% %i18n:@save-created-theme%</ui-button> <ui-button primary @click="gen()"><fa :icon="['far', 'save']"/> %i18n:@save-created-theme%</ui-button>
</details> </details>
<details> <details>
<summary>%fa:download% %i18n:@install-a-theme%</summary> <summary><fa icon="download"/> %i18n:@install-a-theme%</summary>
<ui-button @click="import_()">%fa:file-import% %i18n:@import%</ui-button> <ui-button @click="import_()"><fa icon="file-import"/> %i18n:@import%</ui-button>
<input ref="file" type="file" accept=".misskeytheme" style="display:none;" @change="onUpdateImportFile"/> <input ref="file" type="file" accept=".misskeytheme" style="display:none;" @change="onUpdateImportFile"/>
<p>%i18n:@import-by-code%:</p> <p>%i18n:@import-by-code%:</p>
<ui-textarea v-model="installThemeCode"> <ui-textarea v-model="installThemeCode">
<span>%i18n:@theme-code%</span> <span>%i18n:@theme-code%</span>
</ui-textarea> </ui-textarea>
<ui-button @click="() => install(this.installThemeCode)">%fa:check% %i18n:@install%</ui-button> <ui-button @click="() => install(this.installThemeCode)"><fa icon="check"/> %i18n:@install%</ui-button>
</details> </details>
<details> <details>
<summary>%fa:folder-open% %i18n:@manage-themes%</summary> <summary><fa icon="folder-open"/> %i18n:@manage-themes%</summary>
<ui-select v-model="selectedThemeId" placeholder="%i18n:@select-theme%"> <ui-select v-model="selectedThemeId" placeholder="%i18n:@select-theme%">
<optgroup label="%i18n:@builtin-themes%"> <optgroup label="%i18n:@builtin-themes%">
<option v-for="x in builtinThemes" :value="x.id" :key="x.id">{{ x.name }}</option> <option v-for="x in builtinThemes" :value="x.id" :key="x.id">{{ x.name }}</option>
@@ -89,8 +89,8 @@
<ui-textarea readonly :value="selectedThemeCode"> <ui-textarea readonly :value="selectedThemeCode">
<span>%i18n:@theme-code%</span> <span>%i18n:@theme-code%</span>
</ui-textarea> </ui-textarea>
<ui-button @click="export_()" link :download="`${selectedTheme.name}.misskeytheme`" ref="export">%fa:box% %i18n:@export%</ui-button> <ui-button @click="export_()" link :download="`${selectedTheme.name}.misskeytheme`" ref="export"><fa icon="box"/> %i18n:@export%</ui-button>
<ui-button @click="uninstall()" v-if="!builtinThemes.some(t => t.id == selectedTheme.id)">%fa:trash-alt R% %i18n:@uninstall%</ui-button> <ui-button @click="uninstall()" v-if="!builtinThemes.some(t => t.id == selectedTheme.id)"><fa :icon="['far', 'trash-alt']"/> %i18n:@uninstall%</ui-button>
</template> </template>
</details> </details>
</div> </div>

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="csqvmxybqbycalfhkxvyfrgbrdalkaoc"> <div class="csqvmxybqbycalfhkxvyfrgbrdalkaoc">
<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p> <p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p>
<p class="empty" v-else-if="stats.length == 0">%fa:exclamation-circle%%i18n:@empty%</p> <p class="empty" v-else-if="stats.length == 0"><fa icon="exclamation-circle"/>%i18n:@empty%</p>
<!-- トランジションを有効にするとなぜかメモリリークする --> <!-- トランジションを有効にするとなぜかメモリリークする -->
<transition-group v-else tag="div" name="chart"> <transition-group v-else tag="div" name="chart">
<div v-for="stat in stats" :key="stat.tag"> <div v-for="stat in stats" :key="stat.tag">
@@ -58,7 +58,7 @@ export default Vue.extend({
color var(--text) color var(--text)
opacity 0.7 opacity 0.7
> [data-fa] > [data-icon]
margin-right 4px margin-right 4px
> div > div

View File

@@ -1,21 +0,0 @@
<template>
<div class="pfzekjfwkwvadvlujpdnnxfggqgqjoze">
<slot></slot>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({});
</script>
<style lang="stylus" scoped>
.pfzekjfwkwvadvlujpdnnxfggqgqjoze
display flex
> *
flex 1
&:not(:last-child)
margin-right 16px
</style>

View File

@@ -1,5 +1,10 @@
<template> <template>
<component class="dmtdnykelhudezerjlfpbhgovrgnqqgr" :is="link ? 'a' : 'button'" :class="[styl, { inline, primary }]" :type="type" @click="$emit('click')"> <component class="dmtdnykelhudezerjlfpbhgovrgnqqgr"
:is="link ? 'a' : 'button'"
:class="[styl, { inline, primary }]"
:type="type"
@click="$emit('click')"
>
<slot></slot> <slot></slot>
</component> </component>
</template> </template>
@@ -7,6 +12,11 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
export default Vue.extend({ export default Vue.extend({
inject: {
horizonGrouped: {
default: false
}
},
props: { props: {
type: { type: {
type: String, type: String,
@@ -20,7 +30,9 @@ export default Vue.extend({
inline: { inline: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false default(): boolean {
return this.horizonGrouped;
}
}, },
link: { link: {
type: Boolean, type: Boolean,

View File

@@ -48,6 +48,9 @@ export default Vue.extend({
&.fit-top &.fit-top
padding-top 0 padding-top 0
&.fit-bottom
padding-bottom 0
> header > header
margin-bottom 16px margin-bottom 16px
font-weight bold font-weight bold

View File

@@ -0,0 +1,35 @@
<template>
<div class="pfzekjfwkwvadvlujpdnnxfggqgqjoze" :class="{ inputs }">
<slot></slot>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
provide: {
horizonGrouped: true
},
props: {
inputs: {
type: Boolean,
required: false,
default: false
}
}
});
</script>
<style lang="stylus" scoped>
.pfzekjfwkwvadvlujpdnnxfggqgqjoze
display flex
&.inputs
margin 32px 0
> *
flex 1
&:not(:last-child)
margin-right 16px
</style>

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="ymxyweixqwsxauxldgpvecjepnwxbylu" :class="{ warn }"> <div class="ymxyweixqwsxauxldgpvecjepnwxbylu" :class="{ warn }">
<i v-if="warn">%fa:exclamation-triangle%</i> <i v-if="warn"><fa icon="exclamation-triangle"/></i>
<i v-else>%fa:info-circle%</i> <i v-else><fa icon="info-circle"/></i>
<slot></slot> <slot></slot>
</div> </div>
</template> </template>

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="ui-input" :class="[{ focused, filled }, styl]"> <div class="ui-input" :class="[{ focused, filled, inline, disabled }, styl]">
<div class="icon" ref="icon"><slot name="icon"></slot></div> <div class="icon" ref="icon"><slot name="icon"></slot></div>
<div class="input"> <div class="input">
<div class="password-meter" v-if="withPasswordMeter" v-show="passwordStrength != ''" :data-strength="passwordStrength"> <div class="password-meter" v-if="withPasswordMeter" v-show="passwordStrength != ''" :data-strength="passwordStrength">
@@ -11,6 +11,7 @@
<input ref="input" <input ref="input"
:type="type" :type="type"
v-model="v" v-model="v"
:disabled="disabled"
:required="required" :required="required"
:readonly="readonly" :readonly="readonly"
:pattern="pattern" :pattern="pattern"
@@ -32,7 +33,7 @@
</template> </template>
<div class="suffix" ref="suffix"><slot name="suffix"></slot></div> <div class="suffix" ref="suffix"><slot name="suffix"></slot></div>
</div> </div>
<div class="text"><slot name="text"></slot></div> <div class="desc"><slot name="desc"></slot></div>
</div> </div>
</template> </template>
@@ -41,6 +42,11 @@ import Vue from 'vue';
const getPasswordStrength = require('syuilo-password-strength'); const getPasswordStrength = require('syuilo-password-strength');
export default Vue.extend({ export default Vue.extend({
inject: {
horizonGrouped: {
default: false
}
},
props: { props: {
value: { value: {
required: false required: false
@@ -57,6 +63,10 @@ export default Vue.extend({
type: Boolean, type: Boolean,
required: false required: false
}, },
disabled: {
type: Boolean,
required: false
},
pattern: { pattern: {
type: String, type: String,
required: false required: false
@@ -72,6 +82,13 @@ export default Vue.extend({
required: false, required: false,
default: false default: false
}, },
inline: {
type: Boolean,
required: false,
default(): boolean {
return this.horizonGrouped;
}
},
styl: { styl: {
type: String, type: String,
required: false, required: false,
@@ -304,7 +321,7 @@ root(fill)
if fill if fill
padding-right 12px padding-right 12px
> .text > .desc
margin 6px 0 margin 6px 0
font-size 13px font-size 13px
@@ -337,4 +354,14 @@ root(fill)
&:not(.fill) &:not(.fill)
root(false) root(false)
&.inline
display inline-block
margin 0
&.disabled
opacity 0.7
&, *
cursor not-allowed !important
</style> </style>

View File

@@ -129,5 +129,6 @@ export default Vue.extend({
> p > p
margin 0 margin 0
opacity 0.7 opacity 0.7
font-size 90%
</style> </style>

View File

@@ -13,7 +13,7 @@
@blur="focused = false" @blur="focused = false"
></textarea> ></textarea>
</div> </div>
<div class="text"><slot name="text"></slot></div> <div class="desc"><slot name="desc"></slot></div>
</div> </div>
</template> </template>
@@ -139,7 +139,7 @@ root(fill)
outline none outline none
box-shadow none box-shadow none
> .text > .desc
margin 6px 0 margin 6px 0
font-size 13px font-size 13px

View File

@@ -3,7 +3,7 @@
<ol v-if="uploads.length > 0"> <ol v-if="uploads.length > 0">
<li v-for="ctx in uploads" :key="ctx.id"> <li v-for="ctx in uploads" :key="ctx.id">
<div class="img" :style="{ backgroundImage: `url(${ ctx.img })` }"></div> <div class="img" :style="{ backgroundImage: `url(${ ctx.img })` }"></div>
<p class="name">%fa:spinner .pulse%{{ ctx.name }}</p> <p class="name"><fa icon="spinner .pulse"/>{{ ctx.name }}</p>
<p class="status"> <p class="status">
<span class="initing" v-if="ctx.progress == undefined">%i18n:@waiting%<mk-ellipsis/></span> <span class="initing" v-if="ctx.progress == undefined">%i18n:@waiting%<mk-ellipsis/></span>
<span class="kb" v-if="ctx.progress != undefined">{{ String(Math.floor(ctx.progress.value / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }}<i>KB</i> / {{ String(Math.floor(ctx.progress.max / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }}<i>KB</i></span> <span class="kb" v-if="ctx.progress != undefined">{{ String(Math.floor(ctx.progress.value / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }}<i>KB</i> / {{ String(Math.floor(ctx.progress.max / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }}<i>KB</i></span>
@@ -155,7 +155,7 @@ export default Vue.extend({
text-overflow ellipsis text-overflow ellipsis
overflow hidden overflow hidden
> [data-fa] > [data-icon]
margin-right 4px margin-right 4px
> .status > .status

View File

@@ -6,7 +6,7 @@
<span class="pathname" v-if="pathname != ''">{{ pathname }}</span> <span class="pathname" v-if="pathname != ''">{{ pathname }}</span>
<span class="query">{{ query }}</span> <span class="query">{{ query }}</span>
<span class="hash">{{ hash }}</span> <span class="hash">{{ hash }}</span>
%fa:external-link-square-alt% <fa icon="external-link-square-alt"/>
</a> </a>
</template> </template>
@@ -40,7 +40,7 @@ export default Vue.extend({
<style lang="stylus" scoped> <style lang="stylus" scoped>
.mk-url .mk-url
word-break break-all word-break break-all
> [data-fa] > [data-icon]
padding-left 2px padding-left 2px
font-size .9em font-size .9em
font-weight 400 font-weight 400

View File

@@ -3,34 +3,34 @@
<div class="backdrop" ref="backdrop" @click="close"></div> <div class="backdrop" ref="backdrop" @click="close"></div>
<div class="popover" :class="{ compact }" ref="popover"> <div class="popover" :class="{ compact }" ref="popover">
<div @click="choose('public')" :class="{ active: v == 'public' }"> <div @click="choose('public')" :class="{ active: v == 'public' }">
<div>%fa:globe%</div> <div><fa icon="globe"/></div>
<div> <div>
<span>%i18n:@public%</span> <span>%i18n:@public%</span>
</div> </div>
</div> </div>
<div @click="choose('home')" :class="{ active: v == 'home' }"> <div @click="choose('home')" :class="{ active: v == 'home' }">
<div>%fa:home%</div> <div><fa icon="home"/></div>
<div> <div>
<span>%i18n:@home%</span> <span>%i18n:@home%</span>
<span>%i18n:@home-desc%</span> <span>%i18n:@home-desc%</span>
</div> </div>
</div> </div>
<div @click="choose('followers')" :class="{ active: v == 'followers' }"> <div @click="choose('followers')" :class="{ active: v == 'followers' }">
<div>%fa:unlock%</div> <div><fa icon="unlock"/></div>
<div> <div>
<span>%i18n:@followers%</span> <span>%i18n:@followers%</span>
<span>%i18n:@followers-desc%</span> <span>%i18n:@followers-desc%</span>
</div> </div>
</div> </div>
<div @click="choose('specified')" :class="{ active: v == 'specified' }"> <div @click="choose('specified')" :class="{ active: v == 'specified' }">
<div>%fa:envelope%</div> <div><fa icon="envelope"/></div>
<div> <div>
<span>%i18n:@specified%</span> <span>%i18n:@specified%</span>
<span>%i18n:@specified-desc%</span> <span>%i18n:@specified-desc%</span>
</div> </div>
</div> </div>
<div @click="choose('private')" :class="{ active: v == 'private' }"> <div @click="choose('private')" :class="{ active: v == 'private' }">
<div>%fa:lock%</div> <div><fa icon="lock"/></div>
<div> <div>
<span>%i18n:@private%</span> <span>%i18n:@private%</span>
</div> </div>

View File

@@ -14,7 +14,7 @@
</div> </div>
</header> </header>
<div class="text"> <div class="text">
<misskey-flavored-markdown v-if="note.text" :text="note.text" :customEmojis="p.emojis"/> <misskey-flavored-markdown v-if="note.text" :text="note.text" :customEmojis="note.emojis"/>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -109,7 +109,7 @@ class Autocomplete {
if (isEmoji && opened == false) { if (isEmoji && opened == false) {
const emoji = text.substr(emojiIndex + 1); const emoji = text.substr(emojiIndex + 1);
if (emoji != '' && emoji.match(/^[\+\-a-z0-9_]+$/)) { if (!emoji.includes(' ')) {
this.open('emoji', emoji); this.open('emoji', emoji);
opened = true; opened = true;
} }
@@ -145,6 +145,7 @@ class Autocomplete {
} else { } else {
// サジェスト要素作成 // サジェスト要素作成
this.suggestion = new MkAutocomplete({ this.suggestion = new MkAutocomplete({
parent: this.vm,
propsData: { propsData: {
textarea: this.textarea, textarea: this.textarea,
complete: this.complete, complete: this.complete,
@@ -222,8 +223,6 @@ class Autocomplete {
const trimmedBefore = before.substring(0, before.lastIndexOf(':')); const trimmedBefore = before.substring(0, before.lastIndexOf(':'));
const after = source.substr(caret); const after = source.substr(caret);
if (value.startsWith(':')) value = value + ' ';
// 挿入 // 挿入
this.text = trimmedBefore + value + after; this.text = trimmedBefore + value + after;

View File

@@ -19,13 +19,13 @@
@click="onClick" @click="onClick"
:disabled="followWait"> :disabled="followWait">
<template v-if="!followWait"> <template v-if="!followWait">
<template v-if="user.hasPendingFollowRequestFromYou && user.isLocked">%fa:hourglass-half% %i18n:@request-pending%</template> <template v-if="user.hasPendingFollowRequestFromYou && user.isLocked"><fa icon="hourglass-half"/> %i18n:@request-pending%</template>
<template v-else-if="user.hasPendingFollowRequestFromYou && !user.isLocked">%fa:hourglass-start% %i18n:@follow-processing%</template> <template v-else-if="user.hasPendingFollowRequestFromYou && !user.isLocked"><fa icon="hourglass-start"/> %i18n:@follow-processing%</template>
<template v-else-if="user.isFollowing">%fa:minus% %i18n:@following%</template> <template v-else-if="user.isFollowing"><fa icon="minus"/> %i18n:@following%</template>
<template v-else-if="!user.isFollowing && user.isLocked">%fa:plus% %i18n:@follow-request%</template> <template v-else-if="!user.isFollowing && user.isLocked"><fa icon="plus"/> %i18n:@follow-request%</template>
<template v-else-if="!user.isFollowing && !user.isLocked">%fa:plus% %i18n:@follow%</template> <template v-else-if="!user.isFollowing && !user.isLocked"><fa icon="plus"/> %i18n:@follow%</template>
</template> </template>
<template v-else>%fa:spinner .pulse .fw%</template> <template v-else><fa icon="spinner .pulse" fixed-width/></template>
</button> </button>
</div> </div>
</template> </template>

View File

@@ -2,7 +2,7 @@
<div> <div>
<mk-widget-container :show-header="false"> <mk-widget-container :show-header="false">
<article class="dolfvtibguprpxxhfndqaosjitixjohx"> <article class="dolfvtibguprpxxhfndqaosjitixjohx">
<h1>%fa:heart%%i18n:@title%</h1> <h1><fa icon="heart"/>%i18n:@title%</h1>
<p v-if="meta"> <p v-if="meta">
{{ '%i18n:@text%'.substr(0, '%i18n:@text%'.indexOf('{')) }} {{ '%i18n:@text%'.substr(0, '%i18n:@text%'.indexOf('{')) }}
<a :href="meta.maintainer.url">{{ meta.maintainer.name }}</a> <a :href="meta.maintainer.url">{{ meta.maintainer.name }}</a>
@@ -41,7 +41,7 @@ export default define({
margin 0 0 5px 0 margin 0 0 5px 0
font-size 1em font-size 1em
> [data-fa] > [data-icon]
margin-right 0.25em margin-right 0.25em
> p > p

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="mkw-hashtags"> <div class="mkw-hashtags">
<mk-widget-container :show-header="!props.compact"> <mk-widget-container :show-header="!props.compact">
<template slot="header">%fa:hashtag%%i18n:@title%</template> <template slot="header"><fa icon="hashtag"/>%i18n:@title%</template>
<div class="mkw-hashtags--body" :data-mobile="platform == 'mobile'"> <div class="mkw-hashtags--body" :data-mobile="platform == 'mobile'">
<mk-trends/> <mk-trends/>

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="mkw-memo"> <div class="mkw-memo">
<mk-widget-container :show-header="!props.compact"> <mk-widget-container :show-header="!props.compact">
<template slot="header">%fa:R sticky-note%%i18n:@title%</template> <template slot="header"><fa :icon="['far', 'sticky-note']"/>%i18n:@title%</template>
<div class="mkw-memo--body"> <div class="mkw-memo--body">
<textarea v-model="text" placeholder="%i18n:@memo%" @input="onChange"></textarea> <textarea v-model="text" placeholder="%i18n:@memo%" @input="onChange"></textarea>

View File

@@ -1,9 +1,9 @@
<template> <template>
<div class="mkw-photo-stream" :class="$style.root" :data-melt="props.design == 2"> <div class="mkw-photo-stream" :class="$style.root" :data-melt="props.design == 2">
<mk-widget-container :show-header="props.design == 0" :naked="props.design == 2"> <mk-widget-container :show-header="props.design == 0" :naked="props.design == 2">
<template slot="header">%fa:camera%%i18n:@title%</template> <template slot="header"><fa icon="camera"/>%i18n:@title%</template>
<p :class="$style.fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p> <p :class="$style.fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p>
<div :class="$style.stream" v-if="!fetching && images.length > 0"> <div :class="$style.stream" v-if="!fetching && images.length > 0">
<div v-for="image in images" :class="$style.img" :style="`background-image: url(${image.thumbnailUrl || image.url})`"></div> <div v-for="image in images" :class="$style.img" :style="`background-image: url(${image.thumbnailUrl || image.url})`"></div>
</div> </div>
@@ -94,7 +94,7 @@ export default define({
text-align center text-align center
color #aaa color #aaa
> [data-fa] > [data-icon]
margin-right 4px margin-right 4px
</style> </style>

View File

@@ -1,8 +1,8 @@
<template> <template>
<div class="mkw-posts-monitor"> <div class="mkw-posts-monitor">
<mk-widget-container :show-header="props.design == 0" :naked="props.design == 2"> <mk-widget-container :show-header="props.design == 0" :naked="props.design == 2">
<template slot="header">%fa:chart-line%%i18n:@title%</template> <template slot="header"><fa icon="chart-line"/>%i18n:@title%</template>
<button slot="func" @click="toggle" title="%i18n:@toggle%">%fa:sort%</button> <button slot="func" @click="toggle" title="%i18n:@toggle%"><fa icon="sort"/></button>
<div class="qpdmibaztplkylerhdbllwcokyrfxeyj" :class="{ dual: props.view == 0 }"> <div class="qpdmibaztplkylerhdbllwcokyrfxeyj" :class="{ dual: props.view == 0 }">
<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`" v-show="props.view != 2"> <svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`" v-show="props.view != 2">

View File

@@ -1,11 +1,11 @@
<template> <template>
<div class="mkw-rss"> <div class="mkw-rss">
<mk-widget-container :show-header="!props.compact"> <mk-widget-container :show-header="!props.compact">
<template slot="header">%fa:rss-square%RSS</template> <template slot="header"><fa icon="rss-square"/>RSS</template>
<button slot="func" title="設定" @click="setting">%fa:cog%</button> <button slot="func" title="設定" @click="setting"><fa icon="cog"/></button>
<div class="mkw-rss--body" :data-mobile="platform == 'mobile'"> <div class="mkw-rss--body" :data-mobile="platform == 'mobile'">
<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p> <p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p>
<div class="feed" v-else> <div class="feed" v-else>
<a v-for="item in items" :href="item.link" target="_blank">{{ item.title }}</a> <a v-for="item in items" :href="item.link" target="_blank">{{ item.title }}</a>
</div> </div>
@@ -85,7 +85,7 @@ export default define({
text-align center text-align center
color #aaa color #aaa
> [data-fa] > [data-icon]
margin-right 4px margin-right 4px
&[data-mobile] &[data-mobile]

View File

@@ -2,7 +2,7 @@
<div class="cpu"> <div class="cpu">
<x-pie class="pie" :value="usage"/> <x-pie class="pie" :value="usage"/>
<div> <div>
<p>%fa:microchip%CPU</p> <p><fa icon="microchip"/>CPU</p>
<p>{{ meta.cpu.cores }} Cores</p> <p>{{ meta.cpu.cores }} Cores</p>
<p>{{ meta.cpu.model }}</p> <p>{{ meta.cpu.model }}</p>
</div> </div>
@@ -57,7 +57,7 @@ export default Vue.extend({
&:first-child &:first-child
font-weight bold font-weight bold
> [data-fa] > [data-icon]
margin-right 4px margin-right 4px
&:after &:after

View File

@@ -2,7 +2,7 @@
<div class="disk"> <div class="disk">
<x-pie class="pie" :value="usage"/> <x-pie class="pie" :value="usage"/>
<div> <div>
<p>%fa:R hdd%Storage</p> <p><fa :icon="['far', 'hdd']"/>Storage</p>
<p>Total: {{ total | bytes(1) }}</p> <p>Total: {{ total | bytes(1) }}</p>
<p>Free: {{ available | bytes(1) }}</p> <p>Free: {{ available | bytes(1) }}</p>
<p>Used: {{ used | bytes(1) }}</p> <p>Used: {{ used | bytes(1) }}</p>
@@ -65,7 +65,7 @@ export default Vue.extend({
&:first-child &:first-child
font-weight bold font-weight bold
> [data-fa] > [data-icon]
margin-right 4px margin-right 4px
&:after &:after

View File

@@ -2,7 +2,7 @@
<div class="memory"> <div class="memory">
<x-pie class="pie" :value="usage"/> <x-pie class="pie" :value="usage"/>
<div> <div>
<p>%fa:flask%Memory</p> <p><fa icon="flask"/>Memory</p>
<p>Total: {{ total | bytes(1) }}</p> <p>Total: {{ total | bytes(1) }}</p>
<p>Used: {{ used | bytes(1) }}</p> <p>Used: {{ used | bytes(1) }}</p>
<p>Free: {{ free | bytes(1) }}</p> <p>Free: {{ free | bytes(1) }}</p>
@@ -65,7 +65,7 @@ export default Vue.extend({
&:first-child &:first-child
font-weight bold font-weight bold
> [data-fa] > [data-icon]
margin-right 4px margin-right 4px
&:after &:after

View File

@@ -1,10 +1,10 @@
<template> <template>
<div class="mkw-server"> <div class="mkw-server">
<mk-widget-container :show-header="props.design == 0" :naked="props.design == 2"> <mk-widget-container :show-header="props.design == 0" :naked="props.design == 2">
<template slot="header">%fa:server%%i18n:@title%</template> <template slot="header"><fa icon="server"/>%i18n:@title%</template>
<button slot="func" @click="toggle" title="%i18n:@toggle%">%fa:sort%</button> <button slot="func" @click="toggle" title="%i18n:@toggle%"><fa icon="sort"/></button>
<p :class="$style.fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p> <p :class="$style.fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p>
<template v-if="!fetching"> <template v-if="!fetching">
<x-cpu-memory v-show="props.view == 0" :connection="connection"/> <x-cpu-memory v-show="props.view == 0" :connection="connection"/>
<x-cpu v-show="props.view == 1" :connection="connection" :meta="meta"/> <x-cpu v-show="props.view == 1" :connection="connection" :meta="meta"/>
@@ -87,7 +87,7 @@ export default define({
text-align center text-align center
color #aaa color #aaa
> [data-fa] > [data-icon]
margin-right 4px margin-right 4px
</style> </style>

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="mkw-tips"> <div class="mkw-tips">
<p ref="tip">%fa:R lightbulb%<span v-html="tip"></span></p> <p ref="tip"><fa :icon="['far', 'lightbulb']"/><span v-html="tip"></span></p>
</div> </div>
</template> </template>
@@ -88,7 +88,7 @@ export default define({
font-size 0.7em font-size 0.7em
color #999 color #999
> [data-fa] > [data-icon]
margin-right 4px margin-right 4px
kbd kbd

View File

@@ -23,7 +23,6 @@ import updateBanner from './api/update-banner';
import MkIndex from './views/pages/index.vue'; import MkIndex from './views/pages/index.vue';
import MkHome from './views/pages/home.vue'; import MkHome from './views/pages/home.vue';
import MkDeck from './views/pages/deck/deck.vue'; import MkDeck from './views/pages/deck/deck.vue';
import MkStats from './views/pages/stats/stats.vue';
import MkUser from './views/pages/user/user.vue'; import MkUser from './views/pages/user/user.vue';
import MkFavorites from './views/pages/favorites.vue'; import MkFavorites from './views/pages/favorites.vue';
import MkSelectDrive from './views/pages/selectdrive.vue'; import MkSelectDrive from './views/pages/selectdrive.vue';
@@ -56,7 +55,6 @@ init(async (launch) => {
{ path: '/', name: 'index', component: MkIndex }, { path: '/', name: 'index', component: MkIndex },
{ path: '/home', name: 'home', component: MkHome }, { path: '/home', name: 'home', component: MkHome },
{ path: '/deck', name: 'deck', component: MkDeck }, { path: '/deck', name: 'deck', component: MkDeck },
{ path: '/stats', name: 'stats', component: MkStats },
{ path: '/i/customize-home', component: MkHomeCustomize }, { path: '/i/customize-home', component: MkHomeCustomize },
{ path: '/i/favorites', component: MkFavorites }, { path: '/i/favorites', component: MkFavorites },
{ path: '/i/messaging/:user', component: MkMessagingRoom }, { path: '/i/messaging/:user', component: MkMessagingRoom },

View File

@@ -1,10 +1,10 @@
<template> <template>
<div class="mk-activity"> <div class="mk-activity">
<mk-widget-container :show-header="design == 0" :naked="design == 2"> <mk-widget-container :show-header="design == 0" :naked="design == 2">
<template slot="header">%fa:chart-bar%%i18n:@title%</template> <template slot="header"><fa icon="chart-bar"/>%i18n:@title%</template>
<button slot="func" title="%i18n:@toggle%" @click="toggle">%fa:sort%</button> <button slot="func" title="%i18n:@toggle%" @click="toggle"><fa icon="sort"/></button>
<p :class="$style.fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p> <p :class="$style.fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:common.loading%<mk-ellipsis/></p>
<template v-else> <template v-else>
<x-calendar v-show="view == 0" :data="[].concat(activity)"/> <x-calendar v-show="view == 0" :data="[].concat(activity)"/>
<x-chart v-show="view == 1" :data="[].concat(activity)"/> <x-chart v-show="view == 1" :data="[].concat(activity)"/>
@@ -78,7 +78,7 @@ export default Vue.extend({
text-align center text-align center
color #aaa color #aaa
> [data-fa] > [data-icon]
margin-right 4px margin-right 4px
</style> </style>

View File

@@ -1,9 +1,9 @@
<template> <template>
<div class="mk-calendar" :data-melt="design == 4 || design == 5"> <div class="mk-calendar" :data-melt="design == 4 || design == 5">
<template v-if="design == 0 || design == 1"> <template v-if="design == 0 || design == 1">
<button @click="prev" title="%i18n:@prev%">%fa:chevron-circle-left%</button> <button @click="prev" title="%i18n:@prev%"><fa icon="chevron-circle-left"/></button>
<p class="title">{{ '%i18n:@title%'.replace('{1}', year).replace('{2}', month) }}</p> <p class="title">{{ '%i18n:@title%'.replace('{1}', year).replace('{2}', month) }}</p>
<button @click="next" title="%i18n:@next%">%fa:chevron-circle-right%</button> <button @click="next" title="%i18n:@next%"><fa icon="chevron-circle-right"/></button>
</template> </template>
<div class="calendar"> <div class="calendar">
@@ -151,7 +151,7 @@ export default Vue.extend({
background var(--faceHeader) background var(--faceHeader)
box-shadow 0 1px rgba(#000, 0.07) box-shadow 0 1px rgba(#000, 0.07)
> [data-fa] > [data-icon]
margin-right 4px margin-right 4px
> button > button

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