Compare commits
	
		
			93 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 3b505709c6 | ||
|   | af32d1f81e | ||
|   | 67d8773e38 | ||
|   | e445d39c2f | ||
|   | 961ed969db | ||
|   | e9a3495225 | ||
|   | 6c5a78aeb2 | ||
|   | 34e249317a | ||
|   | 6d8ea89f09 | ||
|   | 64f89ba13e | ||
|   | f6b2f76bbf | ||
|   | 1235bef038 | ||
|   | 2e11f3a843 | ||
|   | 84b7e0bb7d | ||
|   | 9f5dc2c0df | ||
|   | e640dbc501 | ||
|   | 85db090d9f | ||
|   | 9f2d8e1d51 | ||
|   | 0c98a90b75 | ||
|   | 0047920c1a | ||
|   | e4bb534f20 | ||
|   | 3fc04fcdc5 | ||
|   | e542dcac30 | ||
|   | a0b13505a0 | ||
|   | 389f9bfea2 | ||
|   | 630a534cee | ||
|   | 5744c391e6 | ||
|   | b9b05a7401 | ||
|   | 359470a263 | ||
|   | 3fe934ee62 | ||
|   | 3abe632f06 | ||
|   | 65961bc15b | ||
|   | 12f932d48a | ||
|   | 54e9147782 | ||
|   | 31b7626d01 | ||
|   | 200ebefe92 | ||
|   | 9d29a2e85a | ||
|   | c62a225542 | ||
|   | d5d995a3e6 | ||
|   | b7f10fdc10 | ||
|   | cbba03b376 | ||
|   | f84e9c7dc8 | ||
|   | a22ddb1fb9 | ||
|   | 0d23ce3d45 | ||
|   | 9719387bee | ||
|   | dca110ebaa | ||
|   | 136f23c7ad | ||
|   | 0963e6d6e1 | ||
|   | 712802e682 | ||
|   | abe99c3c73 | ||
|   | d7a3b71028 | ||
|   | 10c434f24a | ||
|   | fe46c53ea6 | ||
|   | cdd123dfd3 | ||
|   | a1a3ee44b5 | ||
|   | 4e7fbd8967 | ||
|   | a86c419f95 | ||
|   | e3ec0ad97e | ||
|   | 75791981ce | ||
|   | e813fe16b9 | ||
|   | 42ac7b954d | ||
|   | c1bbf5dab6 | ||
|   | e16dc2a910 | ||
|   | e236c05d79 | ||
|   | 454c1e3faf | ||
|   | 43daf814df | ||
|   | c40b630530 | ||
|   | 7fc0698ecf | ||
|   | 4f3c8b940e | ||
|   | 1855ab60f1 | ||
|   | af4f1a7bd6 | ||
|   | 8646a9c49c | ||
|   | 8d7c033cf5 | ||
|   | b8900e32de | ||
|   | d48c25d2c9 | ||
|   | a87c5899c5 | ||
|   | 147ad69864 | ||
|   | c146006476 | ||
|   | a0f10d7ca1 | ||
|   | 299b91edc4 | ||
|   | 95c89ca6db | ||
|   | 7fe0d71e7f | ||
|   | fbbb506e86 | ||
|   | ec80b06a45 | ||
|   | 41e1619f1f | ||
|   | ba6a9c6a93 | ||
|   | 18571c52fb | ||
|   | 5d5dfeaa83 | ||
|   | 3669d8c0f3 | ||
|   | 69d72819c6 | ||
|   | 54dcc10250 | ||
|   | 1edfce8f73 | ||
|   | 675e573a8c | 
| @@ -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,6 +39,7 @@ jobs: | |||||||
|           name: Install Dependencies |           name: Install Dependencies | ||||||
|           command: | |           command: | | ||||||
|             npm install |             npm install | ||||||
|  |             npm prune | ||||||
|       - run: |       - run: | ||||||
|           name: Configure |           name: Configure | ||||||
|           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: | ||||||
|   | |||||||
| @@ -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 | ||||||
| @@ -148,6 +145,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 +167,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 |  | ||||||
|   | |||||||
							
								
								
									
										41
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								.travis.yml
									
									
									
									
									
								
							| @@ -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 |  | ||||||
| @@ -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`. | ||||||
|   | |||||||
| @@ -4,7 +4,6 @@ | |||||||
| ================================================================ | ================================================================ | ||||||
|  |  | ||||||
| [](https://circleci.com/gh/syuilo/misskey) | [](https://circleci.com/gh/syuilo/misskey) | ||||||
| [![][travis-badge]][travis-link] |  | ||||||
| [![][dependencies-badge]][dependencies-link] | [![][dependencies-badge]][dependencies-link] | ||||||
| [](http://makeapullrequest.com) | [](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 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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以上) | ||||||
|  |  | ||||||
| ##### オプション | ##### オプション | ||||||
|   | |||||||
| @@ -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({ | ||||||
|   | |||||||
| @@ -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からドライブにファイルをアップロード" | ||||||
| @@ -1088,10 +1072,18 @@ admin/views/dashboard.vue: | |||||||
|   instances: "インスタンス" |   instances: "インスタンス" | ||||||
|   this-instance: "このインスタンス" |   this-instance: "このインスタンス" | ||||||
|   federated: "連合" |   federated: "連合" | ||||||
|  |  | ||||||
|  | admin/views/instance.vue: | ||||||
|  |   instance: "インスタンス" | ||||||
|  |   instance-name: "インスタンス名" | ||||||
|  |   instance-description: "インスタンスの紹介" | ||||||
|  |   banner-url: "バナー画像URL" | ||||||
|  |   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,10 +1134,16 @@ admin/views/emoji.vue: | |||||||
|     aliases-desc: "スペースで区切って複数設定できます。" |     aliases-desc: "スペースで区切って複数設定できます。" | ||||||
|     url: "絵文字画像URL" |     url: "絵文字画像URL" | ||||||
|     add: "追加" |     add: "追加" | ||||||
|  |     info: "50KB以下のPNG画像をおすすめします。" | ||||||
|  |     added: "絵文字を登録しました" | ||||||
|   emojis: |   emojis: | ||||||
|     title: "絵文字一覧" |     title: "絵文字一覧" | ||||||
|     update: "更新" |     update: "更新" | ||||||
|     remove: "削除" |     remove: "削除" | ||||||
|  |   updated: "更新しました" | ||||||
|  |   remove-emoji: | ||||||
|  |     are-you-sure: "「$1」を削除しますか?" | ||||||
|  |     removed: "削除しました" | ||||||
|  |  | ||||||
| admin/views/announcements.vue: | admin/views/announcements.vue: | ||||||
|   announcements: "お知らせ" |   announcements: "お知らせ" | ||||||
| @@ -1154,6 +1152,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" | ||||||
| @@ -1173,12 +1175,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: "わかった" | ||||||
| @@ -1560,6 +1556,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: "最新のバージョン:" | ||||||
|   | |||||||
| @@ -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: "投稿の積算" | ||||||
| @@ -1387,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: "画像" | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,8 +1,8 @@ | |||||||
| { | { | ||||||
| 	"name": "misskey", | 	"name": "misskey", | ||||||
| 	"author": "syuilo <i@syuilo.com>", | 	"author": "syuilo <i@syuilo.com>", | ||||||
| 	"version": "10.38.2", | 	"version": "10.40.1", | ||||||
| 	"clientVersion": "1.0.11486", | 	"clientVersion": "1.0.11579", | ||||||
| 	"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", | ||||||
| @@ -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", | ||||||
|   | |||||||
| @@ -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.$swal({ | ||||||
|  | 				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.announcements = this.announcements.filter((_, j) => j !== i); | ||||||
| 			this.save(); | 				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> | ||||||
|   | |||||||
| @@ -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> | ||||||
| @@ -63,9 +63,9 @@ 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(--adminDashboardCardBg) | 	background var(--adminDashboardCardBg) | ||||||
| 	border-radius 8px | 	border-radius 8px | ||||||
| @@ -77,10 +77,10 @@ export default Vue.extend({ | |||||||
| 		border-spacing 0 | 		border-spacing 0 | ||||||
| 		border-collapse collapse | 		border-collapse collapse | ||||||
| 		color var(--adminDashboardCardFg) | 		color var(--adminDashboardCardFg) | ||||||
| 		font-size 15px | 		font-size 14px | ||||||
|  |  | ||||||
| 		thead | 		thead | ||||||
| 			border-bottom solid 2px var(--adminDashboardCardDivider) | 			border-bottom solid 1px var(--adminDashboardCardDivider) | ||||||
|  |  | ||||||
| 			tr | 			tr | ||||||
| 				th | 				th | ||||||
|   | |||||||
| @@ -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> | ||||||
|   | |||||||
| @@ -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> | ||||||
| @@ -168,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> | ||||||
|   | |||||||
| @@ -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,6 +124,11 @@ 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 | ||||||
| @@ -131,10 +136,16 @@ export default Vue.extend({ | |||||||
| 		border-bottom solid 1px var(--adminDashboardHeaderBorder) | 		border-bottom solid 1px var(--adminDashboardHeaderBorder) | ||||||
| 		color var(--adminDashboardHeaderFg) | 		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,7 +163,6 @@ export default Vue.extend({ | |||||||
|  |  | ||||||
| 		> div | 		> div | ||||||
| 			flex 1 | 			flex 1 | ||||||
| 			max-width 300px |  | ||||||
| 			margin-right 16px | 			margin-right 16px | ||||||
| 			color var(--adminDashboardCardFg) | 			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) | ||||||
| @@ -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 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| <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-horizon-group inputs> | ||||||
| 				<ui-input v-model="name"> | 				<ui-input v-model="name"> | ||||||
| 					<span>%i18n:@add-emoji.name%</span> | 					<span>%i18n:@add-emoji.name%</span> | ||||||
| 					<span slot="text">%i18n:@add-emoji.name-desc%</span> | 					<span slot="text">%i18n:@add-emoji.name-desc%</span> | ||||||
| @@ -11,32 +12,34 @@ | |||||||
| 					<span>%i18n:@add-emoji.aliases%</span> | 					<span>%i18n:@add-emoji.aliases%</span> | ||||||
| 					<span slot="text">%i18n:@add-emoji.aliases-desc%</span> | 					<span slot="text">%i18n:@add-emoji.aliases-desc%</span> | ||||||
| 				</ui-input> | 				</ui-input> | ||||||
|  | 			</ui-horizon-group> | ||||||
| 			<ui-input v-model="url"> | 			<ui-input v-model="url"> | ||||||
| 				<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> | 	<ui-card> | ||||||
| 		<div slot="title">%fa:grin R% %i18n:@emojis.title%</div> | 		<div slot="title"><fa :icon="['far', 'grin']"/> %i18n:@emojis.title%</div> | ||||||
| 		<section v-for="emoji in emojis"> | 		<section v-for="emoji in emojis"> | ||||||
| 			<img :src="emoji.url" :alt="emoji.name" style="width: 64px;"/> | 			<img :src="emoji.url" :alt="emoji.name" style="width: 64px;"/> | ||||||
|  | 			<ui-horizon-group inputs> | ||||||
| 				<ui-input v-model="emoji.name"> | 				<ui-input v-model="emoji.name"> | ||||||
| 					<span>%i18n:@add-emoji.name%</span> | 					<span>%i18n:@add-emoji.name%</span> | ||||||
| 				<span slot="text">%i18n:@add-emoji.name-desc%</span> |  | ||||||
| 				</ui-input> | 				</ui-input> | ||||||
| 				<ui-input v-model="emoji.aliases"> | 				<ui-input v-model="emoji.aliases"> | ||||||
| 					<span>%i18n:@add-emoji.aliases%</span> | 					<span>%i18n:@add-emoji.aliases%</span> | ||||||
| 				<span slot="text">%i18n:@add-emoji.aliases-desc%</span> |  | ||||||
| 				</ui-input> | 				</ui-input> | ||||||
|  | 			</ui-horizon-group> | ||||||
| 			<ui-input v-model="emoji.url"> | 			<ui-input v-model="emoji.url"> | ||||||
| 				<span>%i18n:@add-emoji.url%</span> | 				<span>%i18n:@add-emoji.url%</span> | ||||||
| 			</ui-input> | 			</ui-input> | ||||||
| 			<ui-button-group> | 			<ui-horizon-group> | ||||||
| 				<ui-button inline @click="updateEmoji(emoji)">%fa:save R% %i18n:@emojis.update%</ui-button> | 				<ui-button @click="updateEmoji(emoji)"><fa :icon="['far', 'save']"/> %i18n:@emojis.update%</ui-button> | ||||||
| 				<ui-button inline @click="removeEmoji(emoji)">%fa:trash-alt R% %i18n:@emojis.remove%</ui-button> | 				<ui-button @click="removeEmoji(emoji)"><fa :icon="['far', 'trash-alt']"/> %i18n:@emojis.remove%</ui-button> | ||||||
| 			</ui-button-group> | 			</ui-horizon-group> | ||||||
| 		</section> | 		</section> | ||||||
| 	</ui-card> | 	</ui-card> | ||||||
| </div> | </div> | ||||||
| @@ -64,17 +67,24 @@ export default Vue.extend({ | |||||||
| 			(this as any).api('admin/emoji/add', { | 			(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(); | 				this.fetchEmojis(); | ||||||
| 			}).catch(e => { | 			}).catch(e => { | ||||||
| 				(this as any).os.apis.dialog({ text: `Failed ${e}` }); | 				this.$swal({ | ||||||
|  | 					type: 'error', | ||||||
|  | 					text: e | ||||||
|  | 				}); | ||||||
| 			}); | 			}); | ||||||
| 		}, | 		}, | ||||||
|  |  | ||||||
| 		fetchEmojis() { | 		fetchEmojis() { | ||||||
| 			(this as any).api('admin/emoji/list').then(emojis => { | 			(this as any).api('admin/emoji/list').then(emojis => { | ||||||
|  | 				emojis.reverse(); | ||||||
| 				emojis.forEach(e => e.aliases = (e.aliases || []).join(' ')); | 				emojis.forEach(e => e.aliases = (e.aliases || []).join(' ')); | ||||||
| 				this.emojis = emojis; | 				this.emojis = emojis; | ||||||
| 			}); | 			}); | ||||||
| @@ -85,24 +95,51 @@ export default Vue.extend({ | |||||||
| 				id: emoji.id, | 				id: emoji.id, | ||||||
| 				name: emoji.name, | 				name: emoji.name, | ||||||
| 				url: emoji.url, | 				url: emoji.url, | ||||||
| 				aliases: emoji.aliases.split(' ') | 				aliases: emoji.aliases.split(' ').filter(x => x.length > 0) | ||||||
| 			}).then(() => { | 			}).then(() => { | ||||||
| 				(this as any).os.apis.dialog({ text: `Updated` }); | 				this.$swal({ | ||||||
|  | 					type: 'success', | ||||||
|  | 					text: '%i18n:@updated%' | ||||||
|  | 				}); | ||||||
| 			}).catch(e => { | 			}).catch(e => { | ||||||
| 				(this as any).os.apis.dialog({ text: `Failed ${e}` }); | 				this.$swal({ | ||||||
|  | 					type: 'error', | ||||||
|  | 					text: e | ||||||
|  | 				}); | ||||||
| 			}); | 			}); | ||||||
| 		}, | 		}, | ||||||
|  |  | ||||||
| 		removeEmoji(emoji) { | 		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', { | 				(this as any).api('admin/emoji/remove', { | ||||||
| 					id: emoji.id | 					id: emoji.id | ||||||
| 				}).then(() => { | 				}).then(() => { | ||||||
| 				(this as any).os.apis.dialog({ text: `Removed` }); | 					this.$swal({ | ||||||
|  | 						type: 'success', | ||||||
|  | 						text: '%i18n:@remove-emoji.removed%' | ||||||
|  | 					}); | ||||||
| 					this.fetchEmojis(); | 					this.fetchEmojis(); | ||||||
| 				}).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> | ||||||
|  | .tumhkfkmgtvzljezfvmgkeurkfncshbe | ||||||
|  | 	@media (min-width 500px) | ||||||
|  | 		padding 16px | ||||||
|  |  | ||||||
|  | </style> | ||||||
|   | |||||||
| @@ -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}` }); | ||||||
| 			}); | 			}); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -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> | ||||||
|   | |||||||
| @@ -1,9 +1,12 @@ | |||||||
| <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"> | ||||||
| 			<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">%i18n:@banner-url%</ui-input> | ||||||
|  | 			<ui-input v-model="maxNoteTextLength">%i18n:@max-note-text-length%</ui-input> | ||||||
| 			<ui-button @click="updateMeta">%i18n:@save%</ui-button> | 			<ui-button @click="updateMeta">%i18n:@save%</ui-button> | ||||||
| 		</section> | 		</section> | ||||||
| 	</ui-card> | 	</ui-card> | ||||||
| @@ -35,28 +38,61 @@ export default Vue.extend({ | |||||||
| 			disableRegistration: false, | 			disableRegistration: false, | ||||||
| 			disableLocalTimeline: false, | 			disableLocalTimeline: false, | ||||||
| 			bannerUrl: null, | 			bannerUrl: null, | ||||||
|  | 			name: null, | ||||||
|  | 			description: 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.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, | ||||||
|  | 				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> | ||||||
|   | |||||||
| @@ -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> | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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,11 +9,11 @@ | |||||||
| 		<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> | ||||||
| @@ -22,7 +22,7 @@ | |||||||
| 		</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> | ||||||
|   | |||||||
| @@ -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,6 +34,7 @@ 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) => { | ||||||
| @@ -42,7 +44,8 @@ const lib = Object.entries(emojilib.lib).filter((x: any) => { | |||||||
| 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/${x[1].char.codePointAt(0).toString(16)}.svg` | ||||||
| })); | })); | ||||||
|  |  | ||||||
| lib.forEach((x: any) => { | lib.forEach((x: any) => { | ||||||
| @@ -51,7 +54,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/${x[1].char.codePointAt(0).toString(16)}.svg` | ||||||
| 			}); | 			}); | ||||||
| 		}); | 		}); | ||||||
| 	} | 	} | ||||||
| @@ -77,6 +81,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 +115,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 +125,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 +215,11 @@ 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); | ||||||
|  | 					return; | ||||||
|  | 				} | ||||||
|  |  | ||||||
| 				const matched = []; | 				const matched = []; | ||||||
| 				const max = 30; | 				const max = 30; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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> | ||||||
|   | |||||||
| @@ -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> | ||||||
|   | |||||||
							
								
								
									
										82
									
								
								src/client/app/common/views/components/emoji.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/client/app/common/views/components/emoji.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | |||||||
|  | <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) { | ||||||
|  | 			this.url = `https://twemoji.maxcdn.com/2/svg/${this.char.codePointAt(0).toString(16)}.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> | ||||||
| @@ -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> | ||||||
|   | |||||||
| @@ -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> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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> | ||||||
|   | |||||||
							
								
								
									
										63
									
								
								src/client/app/common/views/components/github-setting.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/client/app/common/views/components/github-setting.vue
									
									
									
									
									
										Normal 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> | ||||||
| @@ -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> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -37,12 +37,14 @@ 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 emoji from './emoji.vue'; | ||||||
| import Reversi from './games/reversi/reversi.vue'; | import Reversi from './games/reversi/reversi.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 +92,14 @@ 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-emoji', emoji); | ||||||
| Vue.component('mk-reversi', Reversi); | Vue.component('mk-reversi', Reversi); | ||||||
| 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); | ||||||
|   | |||||||
| @@ -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> | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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> | ||||||
|   | |||||||
| @@ -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]) | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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,25 +187,17 @@ 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)); |  | ||||||
| 						if (customEmoji) { |  | ||||||
| 							return [createElement('img', { |  | ||||||
| 						attrs: { | 						attrs: { | ||||||
| 									src: customEmoji.url, | 							emoji: token.emoji, | ||||||
| 									alt: token.emoji, | 							name: token.name | ||||||
| 									title: token.emoji, | 						}, | ||||||
| 									style: 'height: 2.5em; vertical-align: middle;' | 						props: { | ||||||
|  | 							customEmojis: this.customEmojis || customEmojis | ||||||
| 						} | 						} | ||||||
| 					})]; | 					})]; | ||||||
| 				} | 				} | ||||||
| 					} |  | ||||||
| 					//#endregion |  | ||||||
|  |  | ||||||
| 					const emoji = emojilib.lib[token.emoji]; |  | ||||||
| 					return [createElement('span', emoji ? emoji.char : token.content)]; |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				case 'search': { | 				case 'search': { | ||||||
| 					return [createElement(MkGoogle, { | 					return [createElement(MkGoogle, { | ||||||
|   | |||||||
| @@ -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> | ||||||
|   | |||||||
| @@ -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> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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> | ||||||
|   | |||||||
| @@ -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 | ||||||
| 				}); | 				}); | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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,13 +30,13 @@ | |||||||
|  |  | ||||||
| 			<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="text" 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="text" v-if="bannerUploading">%i18n:@uploading%<mk-ellipsis/></span> | ||||||
| 			</ui-input> | 			</ui-input> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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="text" 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="text" 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="text" 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="text" 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="text" 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="text" 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="text" 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="text" 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="text"> | ||||||
| 				<p slot="text" v-if="passwordStrength == 'low'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@weak-password%</p> | 				<p slot="text" 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 slot="text" 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 slot="text" 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="text"> | ||||||
| 				<p slot="text" v-if="passwordRetypeState == 'match'" style="color:#3CB7B5">%fa:check .fw% %i18n:@password-matched%</p> | 				<p slot="text" 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 slot="text" 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> | ||||||
|   | |||||||
| @@ -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> | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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> | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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> |  | ||||||
| @@ -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, | ||||||
|   | |||||||
							
								
								
									
										35
									
								
								src/client/app/common/views/components/ui/horizon-group.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/client/app/common/views/components/ui/horizon-group.vue
									
									
									
									
									
										Normal 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> | ||||||
| @@ -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> | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| <template> | <template> | ||||||
| <div class="ui-input" :class="[{ focused, filled }, styl]"> | <div class="ui-input" :class="[{ focused, filled, inline }, 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"> | ||||||
| @@ -41,6 +41,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 | ||||||
| @@ -72,6 +77,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, | ||||||
| @@ -337,4 +349,8 @@ root(fill) | |||||||
| 	&:not(.fill) | 	&:not(.fill) | ||||||
| 		root(false) | 		root(false) | ||||||
|  |  | ||||||
|  | 	&.inline | ||||||
|  | 		display inline-block | ||||||
|  | 		margin 0 | ||||||
|  |  | ||||||
| </style> | </style> | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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> | ||||||
|   | |||||||
| @@ -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; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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> | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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/> | ||||||
|   | |||||||
| @@ -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> | ||||||
|   | |||||||
| @@ -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> | ||||||
|   | |||||||
| @@ -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"> | ||||||
|   | |||||||
| @@ -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] | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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> | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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 }, | ||||||
|   | |||||||
| @@ -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> | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -1,42 +0,0 @@ | |||||||
| import Vue from 'vue'; |  | ||||||
| import { Line } from 'vue-chartjs'; |  | ||||||
| import * as mergeOptions from 'merge-options'; |  | ||||||
|  |  | ||||||
| export default Vue.extend({ |  | ||||||
| 	extends: Line, |  | ||||||
| 	props: { |  | ||||||
| 		data: { |  | ||||||
| 			required: true |  | ||||||
| 		}, |  | ||||||
| 		opts: { |  | ||||||
| 			required: false |  | ||||||
| 		} |  | ||||||
| 	}, |  | ||||||
| 	watch: { |  | ||||||
| 		data() { |  | ||||||
| 			this.render(); |  | ||||||
| 		} |  | ||||||
| 	}, |  | ||||||
| 	mounted() { |  | ||||||
| 		this.render(); |  | ||||||
| 	}, |  | ||||||
| 	methods: { |  | ||||||
| 		render() { |  | ||||||
| 			this.renderChart(this.data, mergeOptions({ |  | ||||||
| 				responsive: true, |  | ||||||
| 				maintainAspectRatio: false, |  | ||||||
| 				scales: { |  | ||||||
| 					xAxes: [{ |  | ||||||
| 						type: 'time', |  | ||||||
| 						distribution: 'series' |  | ||||||
| 					}] |  | ||||||
| 				}, |  | ||||||
| 				tooltips: { |  | ||||||
| 					intersect: false, |  | ||||||
| 					mode: 'index', |  | ||||||
| 					position: 'nearest' |  | ||||||
| 				} |  | ||||||
| 			}, this.opts || {})); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| }); |  | ||||||
| @@ -1,723 +0,0 @@ | |||||||
| <template> |  | ||||||
| <div class="gkgckalzgidaygcxnugepioremxvxvpt"> |  | ||||||
| 	<header> |  | ||||||
| 		<b>%i18n:@title%:</b> |  | ||||||
| 		<select v-model="chartType"> |  | ||||||
| 			<optgroup label="%i18n:@federation%"> |  | ||||||
| 				<option value="federation-instances">%i18n:@charts.federation-instances%</option> |  | ||||||
| 				<option value="federation-instances-total">%i18n:@charts.federation-instances-total%</option> |  | ||||||
| 			</optgroup> |  | ||||||
| 			<optgroup label="%i18n:@users%"> |  | ||||||
| 				<option value="users">%i18n:@charts.users%</option> |  | ||||||
| 				<option value="users-total">%i18n:@charts.users-total%</option> |  | ||||||
| 			</optgroup> |  | ||||||
| 			<optgroup label="%i18n:@notes%"> |  | ||||||
| 				<option value="notes">%i18n:@charts.notes%</option> |  | ||||||
| 				<option value="local-notes">%i18n:@charts.local-notes%</option> |  | ||||||
| 				<option value="remote-notes">%i18n:@charts.remote-notes%</option> |  | ||||||
| 				<option value="notes-total">%i18n:@charts.notes-total%</option> |  | ||||||
| 			</optgroup> |  | ||||||
| 			<optgroup label="%i18n:@drive%"> |  | ||||||
| 				<option value="drive-files">%i18n:@charts.drive-files%</option> |  | ||||||
| 				<option value="drive-files-total">%i18n:@charts.drive-files-total%</option> |  | ||||||
| 				<option value="drive">%i18n:@charts.drive%</option> |  | ||||||
| 				<option value="drive-total">%i18n:@charts.drive-total%</option> |  | ||||||
| 			</optgroup> |  | ||||||
| 			<optgroup label="%i18n:@network%"> |  | ||||||
| 				<option value="network-requests">%i18n:@charts.network-requests%</option> |  | ||||||
| 				<option value="network-time">%i18n:@charts.network-time%</option> |  | ||||||
| 				<option value="network-usage">%i18n:@charts.network-usage%</option> |  | ||||||
| 			</optgroup> |  | ||||||
| 		</select> |  | ||||||
| 		<div> |  | ||||||
| 			<span @click="span = 'day'" :class="{ active: span == 'day' }">%i18n:@per-day%</span> | <span @click="span = 'hour'" :class="{ active: span == 'hour' }">%i18n:@per-hour%</span> |  | ||||||
| 		</div> |  | ||||||
| 	</header> |  | ||||||
| 	<div> |  | ||||||
| 		<x-chart v-if="chart" :data="data[0]" :opts="data[1]"/> |  | ||||||
| 	</div> |  | ||||||
| </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script lang="ts"> |  | ||||||
| import Vue from 'vue'; |  | ||||||
| import XChart from './charts.chart.ts'; |  | ||||||
|  |  | ||||||
| const colors = { |  | ||||||
| 	local: 'rgb(246, 88, 79)', |  | ||||||
| 	remote: 'rgb(65, 221, 222)', |  | ||||||
|  |  | ||||||
| 	localPlus: 'rgb(52, 178, 118)', |  | ||||||
| 	remotePlus: 'rgb(158, 255, 209)', |  | ||||||
| 	localMinus: 'rgb(255, 97, 74)', |  | ||||||
| 	remoteMinus: 'rgb(255, 149, 134)', |  | ||||||
|  |  | ||||||
| 	incoming: 'rgb(52, 178, 118)', |  | ||||||
| 	outgoing: 'rgb(255, 97, 74)', |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| const rgba = (color: string): string => { |  | ||||||
| 	return color.replace('rgb', 'rgba').replace(')', ', 0.1)'); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| const limit = 35; |  | ||||||
|  |  | ||||||
| const sum = (...arr) => arr.reduce((r, a) => r.map((b, i) => a[i] + b)); |  | ||||||
| const negate = arr => arr.map(x => -x); |  | ||||||
|  |  | ||||||
| export default Vue.extend({ |  | ||||||
| 	components: { |  | ||||||
| 		XChart |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	data() { |  | ||||||
| 		return { |  | ||||||
| 			now: null, |  | ||||||
| 			chart: null, |  | ||||||
| 			chartType: 'notes', |  | ||||||
| 			span: 'hour' |  | ||||||
| 		}; |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	computed: { |  | ||||||
| 		data(): any { |  | ||||||
| 			if (this.chart == null) return null; |  | ||||||
| 			switch (this.chartType) { |  | ||||||
| 				case 'federation-instances': return this.federationInstancesChart(false); |  | ||||||
| 				case 'federation-instances-total': return this.federationInstancesChart(true); |  | ||||||
| 				case 'users': return this.usersChart(false); |  | ||||||
| 				case 'users-total': return this.usersChart(true); |  | ||||||
| 				case 'notes': return this.notesChart('combined'); |  | ||||||
| 				case 'local-notes': return this.notesChart('local'); |  | ||||||
| 				case 'remote-notes': return this.notesChart('remote'); |  | ||||||
| 				case 'notes-total': return this.notesTotalChart(); |  | ||||||
| 				case 'drive': return this.driveChart(); |  | ||||||
| 				case 'drive-total': return this.driveTotalChart(); |  | ||||||
| 				case 'drive-files': return this.driveFilesChart(); |  | ||||||
| 				case 'drive-files-total': return this.driveFilesTotalChart(); |  | ||||||
| 				case 'network-requests': return this.networkRequestsChart(); |  | ||||||
| 				case 'network-time': return this.networkTimeChart(); |  | ||||||
| 				case 'network-usage': return this.networkUsageChart(); |  | ||||||
| 			} |  | ||||||
| 		}, |  | ||||||
|  |  | ||||||
| 		stats(): any[] { |  | ||||||
| 			const stats = |  | ||||||
| 				this.span == 'day' ? this.chart.perDay : |  | ||||||
| 				this.span == 'hour' ? this.chart.perHour : |  | ||||||
| 				null; |  | ||||||
|  |  | ||||||
| 			return stats; |  | ||||||
| 		} |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	async created() { |  | ||||||
| 		this.now = new Date(); |  | ||||||
|  |  | ||||||
| 		const [perHour, perDay] = await Promise.all([Promise.all([ |  | ||||||
| 			(this as any).api('charts/federation', { limit: limit, span: 'hour' }), |  | ||||||
| 			(this as any).api('charts/users', { limit: limit, span: 'hour' }), |  | ||||||
| 			(this as any).api('charts/notes', { limit: limit, span: 'hour' }), |  | ||||||
| 			(this as any).api('charts/drive', { limit: limit, span: 'hour' }), |  | ||||||
| 			(this as any).api('charts/network', { limit: limit, span: 'hour' }) |  | ||||||
| 		]), Promise.all([ |  | ||||||
| 			(this as any).api('charts/federation', { limit: limit, span: 'day' }), |  | ||||||
| 			(this as any).api('charts/users', { limit: limit, span: 'day' }), |  | ||||||
| 			(this as any).api('charts/notes', { limit: limit, span: 'day' }), |  | ||||||
| 			(this as any).api('charts/drive', { limit: limit, span: 'day' }), |  | ||||||
| 			(this as any).api('charts/network', { limit: limit, span: 'day' }) |  | ||||||
| 		])]); |  | ||||||
|  |  | ||||||
| 		const chart = { |  | ||||||
| 			perHour: { |  | ||||||
| 				federation: perHour[0], |  | ||||||
| 				users: perHour[1], |  | ||||||
| 				notes: perHour[2], |  | ||||||
| 				drive: perHour[3], |  | ||||||
| 				network: perHour[4] |  | ||||||
| 			}, |  | ||||||
| 			perDay: { |  | ||||||
| 				federation: perDay[0], |  | ||||||
| 				users: perDay[1], |  | ||||||
| 				notes: perDay[2], |  | ||||||
| 				drive: perDay[3], |  | ||||||
| 				network: perDay[4] |  | ||||||
| 			} |  | ||||||
| 		}; |  | ||||||
|  |  | ||||||
| 		this.chart = chart; |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	methods: { |  | ||||||
| 		getDate(i: number) { |  | ||||||
| 			const y = this.now.getFullYear(); |  | ||||||
| 			const m = this.now.getMonth(); |  | ||||||
| 			const d = this.now.getDate(); |  | ||||||
| 			const h = this.now.getHours(); |  | ||||||
|  |  | ||||||
| 			return ( |  | ||||||
| 				this.span == 'day' ? new Date(y, m, d - i) : |  | ||||||
| 				this.span == 'hour' ? new Date(y, m, d, h - i) : |  | ||||||
| 				null |  | ||||||
| 			); |  | ||||||
| 		}, |  | ||||||
|  |  | ||||||
| 		format(arr) { |  | ||||||
| 			return arr.map((v, i) => ({ t: this.getDate(i).getTime(), y: v })); |  | ||||||
| 		}, |  | ||||||
|  |  | ||||||
| 		federationInstancesChart(total: boolean): any { |  | ||||||
| 			return [{ |  | ||||||
| 				datasets: [{ |  | ||||||
| 					label: 'Instances', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: rgba(colors.localPlus), |  | ||||||
| 					borderColor: colors.localPlus, |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(total |  | ||||||
| 						? this.stats.federation.instance.total |  | ||||||
| 						: sum(this.stats.federation.instance.inc, negate(this.stats.federation.instance.dec))) |  | ||||||
| 				}] |  | ||||||
| 			}]; |  | ||||||
| 		}, |  | ||||||
|  |  | ||||||
| 		notesChart(type: string): any { |  | ||||||
| 			return [{ |  | ||||||
| 				datasets: [{ |  | ||||||
| 					label: 'All', |  | ||||||
| 					fill: false, |  | ||||||
| 					borderColor: '#555', |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					borderDash: [4, 4], |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(type == 'combined' |  | ||||||
| 						? sum(this.stats.notes.local.inc, negate(this.stats.notes.local.dec), this.stats.notes.remote.inc, negate(this.stats.notes.remote.dec)) |  | ||||||
| 						: sum(this.stats.notes[type].inc, negate(this.stats.notes[type].dec)) |  | ||||||
| 					) |  | ||||||
| 				}, { |  | ||||||
| 					label: 'Renotes', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: 'rgba(161, 222, 65, 0.1)', |  | ||||||
| 					borderColor: '#a1de41', |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(type == 'combined' |  | ||||||
| 						? sum(this.stats.notes.local.diffs.renote, this.stats.notes.remote.diffs.renote) |  | ||||||
| 						: this.stats.notes[type].diffs.renote |  | ||||||
| 					) |  | ||||||
| 				}, { |  | ||||||
| 					label: 'Replies', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: 'rgba(247, 121, 108, 0.1)', |  | ||||||
| 					borderColor: '#f7796c', |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(type == 'combined' |  | ||||||
| 						? sum(this.stats.notes.local.diffs.reply, this.stats.notes.remote.diffs.reply) |  | ||||||
| 						: this.stats.notes[type].diffs.reply |  | ||||||
| 					) |  | ||||||
| 				}, { |  | ||||||
| 					label: 'Normal', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: 'rgba(65, 221, 222, 0.1)', |  | ||||||
| 					borderColor: '#41ddde', |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(type == 'combined' |  | ||||||
| 						? sum(this.stats.notes.local.diffs.normal, this.stats.notes.remote.diffs.normal) |  | ||||||
| 						: this.stats.notes[type].diffs.normal |  | ||||||
| 					) |  | ||||||
| 				}] |  | ||||||
| 			}, { |  | ||||||
| 				scales: { |  | ||||||
| 					yAxes: [{ |  | ||||||
| 						ticks: { |  | ||||||
| 							callback: value => { |  | ||||||
| 								return Vue.filter('number')(value); |  | ||||||
| 							} |  | ||||||
| 						} |  | ||||||
| 					}] |  | ||||||
| 				}, |  | ||||||
| 				tooltips: { |  | ||||||
| 					callbacks: { |  | ||||||
| 						label: (tooltipItem, data) => { |  | ||||||
| 							const label = data.datasets[tooltipItem.datasetIndex].label || ''; |  | ||||||
| 							return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`; |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			}]; |  | ||||||
| 		}, |  | ||||||
|  |  | ||||||
| 		notesTotalChart(): any { |  | ||||||
| 			return [{ |  | ||||||
| 				datasets: [{ |  | ||||||
| 					label: 'Combined', |  | ||||||
| 					fill: false, |  | ||||||
| 					borderColor: '#555', |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					borderDash: [4, 4], |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(sum(this.stats.notes.local.total, this.stats.notes.remote.total)) |  | ||||||
| 				}, { |  | ||||||
| 					label: 'Local', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: rgba(colors.local), |  | ||||||
| 					borderColor: colors.local, |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(this.stats.notes.local.total) |  | ||||||
| 				}, { |  | ||||||
| 					label: 'Remote', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: rgba(colors.remote), |  | ||||||
| 					borderColor: colors.remote, |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(this.stats.notes.remote.total) |  | ||||||
| 				}] |  | ||||||
| 			}, { |  | ||||||
| 				scales: { |  | ||||||
| 					yAxes: [{ |  | ||||||
| 						ticks: { |  | ||||||
| 							callback: value => { |  | ||||||
| 								return Vue.filter('number')(value); |  | ||||||
| 							} |  | ||||||
| 						} |  | ||||||
| 					}] |  | ||||||
| 				}, |  | ||||||
| 				tooltips: { |  | ||||||
| 					callbacks: { |  | ||||||
| 						label: (tooltipItem, data) => { |  | ||||||
| 							const label = data.datasets[tooltipItem.datasetIndex].label || ''; |  | ||||||
| 							return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`; |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			}]; |  | ||||||
| 		}, |  | ||||||
|  |  | ||||||
| 		usersChart(total: boolean): any { |  | ||||||
| 			return [{ |  | ||||||
| 				datasets: [{ |  | ||||||
| 					label: 'Combined', |  | ||||||
| 					fill: false, |  | ||||||
| 					borderColor: '#555', |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					borderDash: [4, 4], |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(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)) |  | ||||||
| 					) |  | ||||||
| 				}, { |  | ||||||
| 					label: 'Local', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: rgba(colors.local), |  | ||||||
| 					borderColor: colors.local, |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(total |  | ||||||
| 						? this.stats.users.local.total |  | ||||||
| 						: sum(this.stats.users.local.inc, negate(this.stats.users.local.dec)) |  | ||||||
| 					) |  | ||||||
| 				}, { |  | ||||||
| 					label: 'Remote', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: rgba(colors.remote), |  | ||||||
| 					borderColor: colors.remote, |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(total |  | ||||||
| 						? this.stats.users.remote.total |  | ||||||
| 						: sum(this.stats.users.remote.inc, negate(this.stats.users.remote.dec)) |  | ||||||
| 					) |  | ||||||
| 				}] |  | ||||||
| 			}, { |  | ||||||
| 				scales: { |  | ||||||
| 					yAxes: [{ |  | ||||||
| 						ticks: { |  | ||||||
| 							callback: value => { |  | ||||||
| 								return Vue.filter('number')(value); |  | ||||||
| 							} |  | ||||||
| 						} |  | ||||||
| 					}] |  | ||||||
| 				}, |  | ||||||
| 				tooltips: { |  | ||||||
| 					callbacks: { |  | ||||||
| 						label: (tooltipItem, data) => { |  | ||||||
| 							const label = data.datasets[tooltipItem.datasetIndex].label || ''; |  | ||||||
| 							return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`; |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			}]; |  | ||||||
| 		}, |  | ||||||
|  |  | ||||||
| 		driveChart(): any { |  | ||||||
| 			return [{ |  | ||||||
| 				datasets: [{ |  | ||||||
| 					label: 'All', |  | ||||||
| 					fill: false, |  | ||||||
| 					borderColor: '#555', |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					borderDash: [4, 4], |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(sum(this.stats.drive.local.incSize, negate(this.stats.drive.local.decSize), this.stats.drive.remote.incSize, negate(this.stats.drive.remote.decSize))) |  | ||||||
| 				}, { |  | ||||||
| 					label: 'Local +', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: rgba(colors.localPlus), |  | ||||||
| 					borderColor: colors.localPlus, |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(this.stats.drive.local.incSize) |  | ||||||
| 				}, { |  | ||||||
| 					label: 'Local -', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: rgba(colors.localMinus), |  | ||||||
| 					borderColor: colors.localMinus, |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(negate(this.stats.drive.local.decSize)) |  | ||||||
| 				}, { |  | ||||||
| 					label: 'Remote +', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: rgba(colors.remotePlus), |  | ||||||
| 					borderColor: colors.remotePlus, |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(this.stats.drive.remote.incSize) |  | ||||||
| 				}, { |  | ||||||
| 					label: 'Remote -', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: rgba(colors.remoteMinus), |  | ||||||
| 					borderColor: colors.remoteMinus, |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(negate(this.stats.drive.remote.decSize)) |  | ||||||
| 				}] |  | ||||||
| 			}, { |  | ||||||
| 				scales: { |  | ||||||
| 					yAxes: [{ |  | ||||||
| 						ticks: { |  | ||||||
| 							callback: value => { |  | ||||||
| 								return Vue.filter('bytes')(value, 1); |  | ||||||
| 							} |  | ||||||
| 						} |  | ||||||
| 					}] |  | ||||||
| 				}, |  | ||||||
| 				tooltips: { |  | ||||||
| 					callbacks: { |  | ||||||
| 						label: (tooltipItem, data) => { |  | ||||||
| 							const label = data.datasets[tooltipItem.datasetIndex].label || ''; |  | ||||||
| 							return `${label}: ${Vue.filter('bytes')(tooltipItem.yLabel, 1)}`; |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			}]; |  | ||||||
| 		}, |  | ||||||
|  |  | ||||||
| 		driveTotalChart(): any { |  | ||||||
| 			return [{ |  | ||||||
| 				datasets: [{ |  | ||||||
| 					label: 'Combined', |  | ||||||
| 					fill: false, |  | ||||||
| 					borderColor: '#555', |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					borderDash: [4, 4], |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(sum(this.stats.drive.local.totalSize, this.stats.drive.remote.totalSize)) |  | ||||||
| 				}, { |  | ||||||
| 					label: 'Local', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: rgba(colors.local), |  | ||||||
| 					borderColor: colors.local, |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(this.stats.drive.local.totalSize) |  | ||||||
| 				}, { |  | ||||||
| 					label: 'Remote', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: rgba(colors.remote), |  | ||||||
| 					borderColor: colors.remote, |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(this.stats.drive.remote.totalSize) |  | ||||||
| 				}] |  | ||||||
| 			}, { |  | ||||||
| 				scales: { |  | ||||||
| 					yAxes: [{ |  | ||||||
| 						ticks: { |  | ||||||
| 							callback: value => { |  | ||||||
| 								return Vue.filter('bytes')(value, 1); |  | ||||||
| 							} |  | ||||||
| 						} |  | ||||||
| 					}] |  | ||||||
| 				}, |  | ||||||
| 				tooltips: { |  | ||||||
| 					callbacks: { |  | ||||||
| 						label: (tooltipItem, data) => { |  | ||||||
| 							const label = data.datasets[tooltipItem.datasetIndex].label || ''; |  | ||||||
| 							return `${label}: ${Vue.filter('bytes')(tooltipItem.yLabel, 1)}`; |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			}]; |  | ||||||
| 		}, |  | ||||||
|  |  | ||||||
| 		driveFilesChart(): any { |  | ||||||
| 			return [{ |  | ||||||
| 				datasets: [{ |  | ||||||
| 					label: 'All', |  | ||||||
| 					fill: false, |  | ||||||
| 					borderColor: '#555', |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					borderDash: [4, 4], |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(sum(this.stats.drive.local.incCount, negate(this.stats.drive.local.decCount), this.stats.drive.remote.incCount, negate(this.stats.drive.remote.decCount))) |  | ||||||
| 				}, { |  | ||||||
| 					label: 'Local +', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: rgba(colors.localPlus), |  | ||||||
| 					borderColor: colors.localPlus, |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(this.stats.drive.local.incCount) |  | ||||||
| 				}, { |  | ||||||
| 					label: 'Local -', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: rgba(colors.localMinus), |  | ||||||
| 					borderColor: colors.localMinus, |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(negate(this.stats.drive.local.decCount)) |  | ||||||
| 				}, { |  | ||||||
| 					label: 'Remote +', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: rgba(colors.remotePlus), |  | ||||||
| 					borderColor: colors.remotePlus, |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(this.stats.drive.remote.incCount) |  | ||||||
| 				}, { |  | ||||||
| 					label: 'Remote -', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: rgba(colors.remoteMinus), |  | ||||||
| 					borderColor: colors.remoteMinus, |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(negate(this.stats.drive.remote.decCount)) |  | ||||||
| 				}] |  | ||||||
| 			}, { |  | ||||||
| 				scales: { |  | ||||||
| 					yAxes: [{ |  | ||||||
| 						ticks: { |  | ||||||
| 							callback: value => { |  | ||||||
| 								return Vue.filter('number')(value); |  | ||||||
| 							} |  | ||||||
| 						} |  | ||||||
| 					}] |  | ||||||
| 				}, |  | ||||||
| 				tooltips: { |  | ||||||
| 					callbacks: { |  | ||||||
| 						label: (tooltipItem, data) => { |  | ||||||
| 							const label = data.datasets[tooltipItem.datasetIndex].label || ''; |  | ||||||
| 							return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`; |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			}]; |  | ||||||
| 		}, |  | ||||||
|  |  | ||||||
| 		driveFilesTotalChart(): any { |  | ||||||
| 			return [{ |  | ||||||
| 				datasets: [{ |  | ||||||
| 					label: 'Combined', |  | ||||||
| 					fill: false, |  | ||||||
| 					borderColor: '#555', |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					borderDash: [4, 4], |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(sum(this.stats.drive.local.totalCount, this.stats.drive.remote.totalCount)) |  | ||||||
| 				}, { |  | ||||||
| 					label: 'Local', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: rgba(colors.local), |  | ||||||
| 					borderColor: colors.local, |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(this.stats.drive.local.totalCount) |  | ||||||
| 				}, { |  | ||||||
| 					label: 'Remote', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: rgba(colors.remote), |  | ||||||
| 					borderColor: colors.remote, |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(this.stats.drive.remote.totalCount) |  | ||||||
| 				}] |  | ||||||
| 			}, { |  | ||||||
| 				scales: { |  | ||||||
| 					yAxes: [{ |  | ||||||
| 						ticks: { |  | ||||||
| 							callback: value => { |  | ||||||
| 								return Vue.filter('number')(value); |  | ||||||
| 							} |  | ||||||
| 						} |  | ||||||
| 					}] |  | ||||||
| 				}, |  | ||||||
| 				tooltips: { |  | ||||||
| 					callbacks: { |  | ||||||
| 						label: (tooltipItem, data) => { |  | ||||||
| 							const label = data.datasets[tooltipItem.datasetIndex].label || ''; |  | ||||||
| 							return `${label}: ${Vue.filter('number')(tooltipItem.yLabel)}`; |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			}]; |  | ||||||
| 		}, |  | ||||||
|  |  | ||||||
| 		networkRequestsChart(): any { |  | ||||||
| 			return [{ |  | ||||||
| 				datasets: [{ |  | ||||||
| 					label: 'Incoming', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: rgba(colors.localPlus), |  | ||||||
| 					borderColor: colors.localPlus, |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(this.stats.network.incomingRequests) |  | ||||||
| 				}] |  | ||||||
| 			}]; |  | ||||||
| 		}, |  | ||||||
|  |  | ||||||
| 		networkTimeChart(): any { |  | ||||||
| 			const data = []; |  | ||||||
|  |  | ||||||
| 			for (let i = 0; i < limit; i++) { |  | ||||||
| 				data.push(this.stats.network.incomingRequests[i] != 0 ? (this.stats.network.totalTime[i] / this.stats.network.incomingRequests[i]) : 0); |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			return [{ |  | ||||||
| 				datasets: [{ |  | ||||||
| 					label: 'Avg time (ms)', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: rgba(colors.localPlus), |  | ||||||
| 					borderColor: colors.localPlus, |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(data) |  | ||||||
| 				}] |  | ||||||
| 			}]; |  | ||||||
| 		}, |  | ||||||
|  |  | ||||||
| 		networkUsageChart(): any { |  | ||||||
| 			return [{ |  | ||||||
| 				datasets: [{ |  | ||||||
| 					label: 'Incoming', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: rgba(colors.incoming), |  | ||||||
| 					borderColor: colors.incoming, |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(this.stats.network.incomingBytes) |  | ||||||
| 				}, { |  | ||||||
| 					label: 'Outgoing', |  | ||||||
| 					fill: true, |  | ||||||
| 					backgroundColor: rgba(colors.outgoing), |  | ||||||
| 					borderColor: colors.outgoing, |  | ||||||
| 					borderWidth: 2, |  | ||||||
| 					pointBackgroundColor: '#fff', |  | ||||||
| 					lineTension: 0, |  | ||||||
| 					data: this.format(this.stats.network.outgoingBytes) |  | ||||||
| 				}] |  | ||||||
| 			}, { |  | ||||||
| 				scales: { |  | ||||||
| 					yAxes: [{ |  | ||||||
| 						ticks: { |  | ||||||
| 							callback: value => { |  | ||||||
| 								return Vue.filter('bytes')(value, 1); |  | ||||||
| 							} |  | ||||||
| 						} |  | ||||||
| 					}] |  | ||||||
| 				}, |  | ||||||
| 				tooltips: { |  | ||||||
| 					callbacks: { |  | ||||||
| 						label: (tooltipItem, data) => { |  | ||||||
| 							const label = data.datasets[tooltipItem.datasetIndex].label || ''; |  | ||||||
| 							return `${label}: ${Vue.filter('bytes')(tooltipItem.yLabel, 1)}`; |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			}]; |  | ||||||
| 		}, |  | ||||||
| 	} |  | ||||||
| }); |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="stylus" scoped> |  | ||||||
| .gkgckalzgidaygcxnugepioremxvxvpt |  | ||||||
| 	padding 32px |  | ||||||
| 	background #fff |  | ||||||
| 	box-shadow 0 2px 8px rgba(#000, 0.1) |  | ||||||
|  |  | ||||||
| 	* |  | ||||||
| 		user-select none |  | ||||||
|  |  | ||||||
| 	> header |  | ||||||
| 		display flex |  | ||||||
| 		margin 0 0 1em 0 |  | ||||||
| 		padding 0 0 8px 0 |  | ||||||
| 		font-size 1em |  | ||||||
| 		color #555 |  | ||||||
| 		border-bottom solid 1px #eee |  | ||||||
|  |  | ||||||
| 		> b |  | ||||||
| 			margin-right 8px |  | ||||||
|  |  | ||||||
| 		> *:last-child |  | ||||||
| 			margin-left auto |  | ||||||
|  |  | ||||||
| 			* |  | ||||||
| 				&:not(.active) |  | ||||||
| 					color var(--primary) |  | ||||||
| 					cursor pointer |  | ||||||
|  |  | ||||||
| 	> div |  | ||||||
| 		> * |  | ||||||
| 			display block |  | ||||||
| 			height 350px |  | ||||||
|  |  | ||||||
| </style> |  | ||||||
| @@ -13,7 +13,7 @@ | |||||||
| 		@change-selection="onChangeSelection" | 		@change-selection="onChangeSelection" | ||||||
| 	/> | 	/> | ||||||
| 	<div :class="$style.footer"> | 	<div :class="$style.footer"> | ||||||
| 		<button :class="$style.upload" title="%i18n:@upload%" @click="upload">%fa:upload%</button> | 		<button :class="$style.upload" title="%i18n:@upload%" @click="upload"><fa icon="upload"/></button> | ||||||
| 		<button :class="$style.cancel" @click="cancel">%i18n:@cancel%</button> | 		<button :class="$style.cancel" @click="cancel">%i18n:@cancel%</button> | ||||||
| 		<button :class="$style.ok" :disabled="multiple && files.length == 0" @click="ok">%i18n:@ok%</button> | 		<button :class="$style.ok" :disabled="multiple && files.length == 0" @click="ok">%i18n:@ok%</button> | ||||||
| 	</div> | 	</div> | ||||||
| @@ -28,7 +28,7 @@ export default Vue.extend({ | |||||||
| 			default: false | 			default: false | ||||||
| 		}, | 		}, | ||||||
| 		title: { | 		title: { | ||||||
| 			default: '%fa:R file%%i18n:@choose-prompt%' | 			default: '<fa :icon="['far', 'file']"/>%i18n:@choose-prompt%' | ||||||
| 		} | 		} | ||||||
| 	}, | 	}, | ||||||
| 	data() { | 	data() { | ||||||
| @@ -62,7 +62,7 @@ export default Vue.extend({ | |||||||
|  |  | ||||||
|  |  | ||||||
| .title | .title | ||||||
| 	> [data-fa] | 	> [data-icon] | ||||||
| 		margin-right 4px | 		margin-right 4px | ||||||
|  |  | ||||||
| .count | .count | ||||||
|   | |||||||
| @@ -21,7 +21,7 @@ import Vue from 'vue'; | |||||||
| export default Vue.extend({ | export default Vue.extend({ | ||||||
| 	props: { | 	props: { | ||||||
| 		title: { | 		title: { | ||||||
| 			default: '%fa:R folder%%i18n:@choose-prompt%' | 			default: '<fa :icon="['far', 'folder']"/>%i18n:@choose-prompt%' | ||||||
| 		} | 		} | ||||||
| 	}, | 	}, | ||||||
| 	methods: { | 	methods: { | ||||||
| @@ -40,7 +40,7 @@ export default Vue.extend({ | |||||||
|  |  | ||||||
|  |  | ||||||
| .title | .title | ||||||
| 	> [data-fa] | 	> [data-icon] | ||||||
| 		margin-right 4px | 		margin-right 4px | ||||||
|  |  | ||||||
| .browser | .browser | ||||||
|   | |||||||
| @@ -3,13 +3,13 @@ | |||||||
| 	<li v-for="(item, i) in menu" :class="item ? item.type : item === null ? 'divider' : null"> | 	<li v-for="(item, i) in menu" :class="item ? item.type : item === null ? 'divider' : null"> | ||||||
| 		<template v-if="item"> | 		<template v-if="item"> | ||||||
| 			<template v-if="item.type == null || item.type == 'item'"> | 			<template v-if="item.type == null || item.type == 'item'"> | ||||||
| 				<p @click="click(item)"><span :class="$style.icon" v-if="item.icon" v-html="item.icon"></span>{{ item.text }}</p> | 				<p @click="click(item)"><i v-if="item.icon" :class="$style.icon"><fa :icon="item.icon"/></i>{{ item.text }}</p> | ||||||
| 			</template> | 			</template> | ||||||
| 			<template v-else-if="item.type == 'link'"> | 			<template v-else-if="item.type == 'link'"> | ||||||
| 				<a :href="item.href" :target="item.target" @click="click(item)"><span :class="$style.icon" v-if="item.icon" v-html="item.icon"></span>{{ item.text }}</a> | 				<a :href="item.href" :target="item.target" @click="click(item)"><i v-if="item.icon" :class="$style.icon"><fa :icon="item.icon"/></i>{{ item.text }}</a> | ||||||
| 			</template> | 			</template> | ||||||
| 			<template v-else-if="item.type == 'nest'"> | 			<template v-else-if="item.type == 'nest'"> | ||||||
| 				<p><span :class="$style.icon" v-if="item.icon" v-html="item.icon"></span>{{ item.text }}...<span class="caret">%fa:caret-right%</span></p> | 				<p><i v-if="item.icon" :class="$style.icon"><fa :icon="item.icon"/></i>{{ item.text }}...<span class="caret"><fa icon="caret-right"/></span></p> | ||||||
| 				<me-nu :menu="item.menu" @x="click"/> | 				<me-nu :menu="item.menu" @x="click"/> | ||||||
| 			</template> | 			</template> | ||||||
| 		</template> | 		</template> | ||||||
| @@ -113,7 +113,7 @@ export default Vue.extend({ | |||||||
|  |  | ||||||
| <style lang="stylus" module> | <style lang="stylus" module> | ||||||
| .icon | .icon | ||||||
| 	> * | 	display inline-block | ||||||
| 	width 28px | 	width 28px | ||||||
| 	margin-left -28px | 	margin-left -28px | ||||||
| 	text-align center | 	text-align center | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| <template> | <template> | ||||||
| 	<mk-window ref="window" is-modal width="800px" :can-close="false"> | 	<mk-window ref="window" is-modal width="800px" :can-close="false"> | ||||||
| 		<span slot="header">%fa:crop%{{ title }}</span> | 		<span slot="header"><fa icon="crop"/>{{ title }}</span> | ||||||
| 		<div class="body"> | 		<div class="body"> | ||||||
| 			<vue-cropper ref="cropper" | 			<vue-cropper ref="cropper" | ||||||
| 				:src="image.url" | 				:src="image.url" | ||||||
| @@ -64,7 +64,7 @@ export default Vue.extend({ | |||||||
|  |  | ||||||
|  |  | ||||||
| .header | .header | ||||||
| 	> [data-fa] | 	> [data-icon] | ||||||
| 		margin-right 4px | 		margin-right 4px | ||||||
|  |  | ||||||
| .img | .img | ||||||
|   | |||||||
| @@ -91,8 +91,6 @@ export default Vue.extend({ | |||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <style lang="stylus" scoped> | <style lang="stylus" scoped> | ||||||
|  |  | ||||||
|  |  | ||||||
| .mk-dialog | .mk-dialog | ||||||
| 	> .bg | 	> .bg | ||||||
| 		display block | 		display block | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
| <mk-window ref="window" @closed="destroyDom" width="800px" height="500px" :popout-url="popout"> | <mk-window ref="window" @closed="destroyDom" width="800px" height="500px" :popout-url="popout"> | ||||||
| 	<template slot="header"> | 	<template slot="header"> | ||||||
| 		<p v-if="usage" :class="$style.info"><b>{{ usage.toFixed(1) }}%</b> %i18n:@used%</p> | 		<p v-if="usage" :class="$style.info"><b>{{ usage.toFixed(1) }}%</b> %i18n:@used%</p> | ||||||
| 		<span :class="$style.title">%fa:cloud%%i18n:common.drive%</span> | 		<span :class="$style.title"><fa icon="cloud"/>%i18n:common.drive%</span> | ||||||
| 	</template> | 	</template> | ||||||
| 	<mk-drive :class="$style.browser" multiple :init-folder="folder" ref="browser"/> | 	<mk-drive :class="$style.browser" multiple :init-folder="folder" ref="browser"/> | ||||||
| </mk-window> | </mk-window> | ||||||
| @@ -39,7 +39,7 @@ export default Vue.extend({ | |||||||
|  |  | ||||||
| <style lang="stylus" module> | <style lang="stylus" module> | ||||||
| .title | .title | ||||||
| 	> [data-fa] | 	> [data-icon] | ||||||
| 		margin-right 4px | 		margin-right 4px | ||||||
|  |  | ||||||
| .info | .info | ||||||
|   | |||||||
| @@ -71,27 +71,27 @@ export default Vue.extend({ | |||||||
| 			contextmenu((this as any).os)(e, [{ | 			contextmenu((this as any).os)(e, [{ | ||||||
| 				type: 'item', | 				type: 'item', | ||||||
| 				text: '%i18n:@contextmenu.rename%', | 				text: '%i18n:@contextmenu.rename%', | ||||||
| 				icon: '%fa:i-cursor%', | 				icon: 'i-cursor', | ||||||
| 				action: this.rename | 				action: this.rename | ||||||
| 			}, { | 			}, { | ||||||
| 				type: 'item', | 				type: 'item', | ||||||
| 				text: this.file.isSensitive ? '%i18n:@contextmenu.unmark-as-sensitive%' : '%i18n:@contextmenu.mark-as-sensitive%', | 				text: this.file.isSensitive ? '%i18n:@contextmenu.unmark-as-sensitive%' : '%i18n:@contextmenu.mark-as-sensitive%', | ||||||
| 				icon: this.file.isSensitive ? '%fa:R eye%' : '%fa:R eye-slash%', | 				icon: this.file.isSensitive ? ['far', 'eye'] : ['far', 'eye-slash'], | ||||||
| 				action: this.toggleSensitive | 				action: this.toggleSensitive | ||||||
| 			}, null, { | 			}, null, { | ||||||
| 				type: 'item', | 				type: 'item', | ||||||
| 				text: '%i18n:@contextmenu.copy-url%', | 				text: '%i18n:@contextmenu.copy-url%', | ||||||
| 				icon: '%fa:link%', | 				icon: 'link', | ||||||
| 				action: this.copyUrl | 				action: this.copyUrl | ||||||
| 			}, { | 			}, { | ||||||
| 				type: 'link', | 				type: 'link', | ||||||
| 				href: `${this.file.url}?download`, | 				href: `${this.file.url}?download`, | ||||||
| 				text: '%i18n:@contextmenu.download%', | 				text: '%i18n:@contextmenu.download%', | ||||||
| 				icon: '%fa:download%', | 				icon: 'download', | ||||||
| 			}, null, { | 			}, null, { | ||||||
| 				type: 'item', | 				type: 'item', | ||||||
| 				text: '%i18n:common.delete%', | 				text: '%i18n:common.delete%', | ||||||
| 				icon: '%fa:R trash-alt%', | 				icon: ['far', 'trash-alt'], | ||||||
| 				action: this.deleteFile | 				action: this.deleteFile | ||||||
| 			}, null, { | 			}, null, { | ||||||
| 				type: 'nest', | 				type: 'nest', | ||||||
| @@ -170,7 +170,7 @@ export default Vue.extend({ | |||||||
| 		copyUrl() { | 		copyUrl() { | ||||||
| 			copyToClipboard(this.file.url); | 			copyToClipboard(this.file.url); | ||||||
| 			(this as any).apis.dialog({ | 			(this as any).apis.dialog({ | ||||||
| 				title: '%fa:check%%i18n:@contextmenu.copied%', | 				title: '<fa icon="check"/>%i18n:@contextmenu.copied%', | ||||||
| 				text: '%i18n:@contextmenu.copied-url-to-clipboard%', | 				text: '%i18n:@contextmenu.copied-url-to-clipboard%', | ||||||
| 				actions: [{ | 				actions: [{ | ||||||
| 					text: '%i18n:common.ok%' | 					text: '%i18n:common.ok%' | ||||||
|   | |||||||
| @@ -16,8 +16,8 @@ | |||||||
| 	:title="title" | 	:title="title" | ||||||
| > | > | ||||||
| 	<p class="name"> | 	<p class="name"> | ||||||
| 		<template v-if="hover">%fa:R folder-open .fw%</template> | 		<template v-if="hover"><fa :icon="['far', 'folder-open']" fixed-width/></template> | ||||||
| 		<template v-if="!hover">%fa:R folder .fw%</template> | 		<template v-if="!hover"><fa :icon="['far', 'folder']" fixed-width/></template> | ||||||
| 		{{ folder.name }} | 		{{ folder.name }} | ||||||
| 	</p> | 	</p> | ||||||
| </div> | </div> | ||||||
| @@ -55,22 +55,22 @@ export default Vue.extend({ | |||||||
| 			contextmenu((this as any).os)(e, [{ | 			contextmenu((this as any).os)(e, [{ | ||||||
| 				type: 'item', | 				type: 'item', | ||||||
| 				text: '%i18n:@contextmenu.move-to-this-folder%', | 				text: '%i18n:@contextmenu.move-to-this-folder%', | ||||||
| 				icon: '%fa:arrow-right%', | 				icon: 'arrow-right', | ||||||
| 				action: this.go | 				action: this.go | ||||||
| 			}, { | 			}, { | ||||||
| 				type: 'item', | 				type: 'item', | ||||||
| 				text: '%i18n:@contextmenu.show-in-new-window%', | 				text: '%i18n:@contextmenu.show-in-new-window%', | ||||||
| 				icon: '%fa:R window-restore%', | 				icon: ['far', 'window-restore'], | ||||||
| 				action: this.newWindow | 				action: this.newWindow | ||||||
| 			}, null, { | 			}, null, { | ||||||
| 				type: 'item', | 				type: 'item', | ||||||
| 				text: '%i18n:@contextmenu.rename%', | 				text: '%i18n:@contextmenu.rename%', | ||||||
| 				icon: '%fa:i-cursor%', | 				icon: 'i-cursor', | ||||||
| 				action: this.rename | 				action: this.rename | ||||||
| 			}, null, { | 			}, null, { | ||||||
| 				type: 'item', | 				type: 'item', | ||||||
| 				text: '%i18n:common.delete%', | 				text: '%i18n:common.delete%', | ||||||
| 				icon: '%fa:R trash-alt%', | 				icon: ['far', 'trash-alt'], | ||||||
| 				action: this.deleteFolder | 				action: this.deleteFolder | ||||||
| 			}], { | 			}], { | ||||||
| 					closed: () => { | 					closed: () => { | ||||||
| @@ -155,7 +155,7 @@ export default Vue.extend({ | |||||||
| 					switch (err) { | 					switch (err) { | ||||||
| 						case 'detected-circular-definition': | 						case 'detected-circular-definition': | ||||||
| 							(this as any).apis.dialog({ | 							(this as any).apis.dialog({ | ||||||
| 								title: '%fa:exclamation-triangle%%i18n:@unable-to-process%', | 								title: '<fa icon="exclamation-triangle"/>%i18n:@unable-to-process%', | ||||||
| 								text: '%i18n:@circular-reference-detected%', | 								text: '%i18n:@circular-reference-detected%', | ||||||
| 								actions: [{ | 								actions: [{ | ||||||
| 									text: '%i18n:common.ok%' | 									text: '%i18n:common.ok%' | ||||||
| @@ -255,7 +255,7 @@ export default Vue.extend({ | |||||||
| 		font-size 0.9em | 		font-size 0.9em | ||||||
| 		color var(--desktopDriveFolderFg) | 		color var(--desktopDriveFolderFg) | ||||||
|  |  | ||||||
| 		> [data-fa] | 		> [data-icon] | ||||||
| 			margin-right 4px | 			margin-right 4px | ||||||
| 			margin-left 2px | 			margin-left 2px | ||||||
| 			text-align left | 			text-align left | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ | |||||||
| 	@dragleave="onDragleave" | 	@dragleave="onDragleave" | ||||||
| 	@drop.stop="onDrop" | 	@drop.stop="onDrop" | ||||||
| > | > | ||||||
| 	<template v-if="folder == null">%fa:cloud%</template> | 	<i v-if="folder == null" class="cloud"><fa icon="cloud"/></i> | ||||||
| 	<span>{{ folder == null ? '%i18n:common.drive%' : folder.name }}</span> | 	<span>{{ folder == null ? '%i18n:common.drive%' : folder.name }}</span> | ||||||
| </div> | </div> | ||||||
| </template> | </template> | ||||||
| @@ -110,7 +110,7 @@ export default Vue.extend({ | |||||||
| 	&[data-draghover] | 	&[data-draghover] | ||||||
| 		background #eee | 		background #eee | ||||||
|  |  | ||||||
| 	[data-fa].cloud | 	i.cloud | ||||||
| 		margin-right 4px | 		margin-right 4px | ||||||
|  |  | ||||||
| </style> | </style> | ||||||
|   | |||||||
| @@ -4,10 +4,10 @@ | |||||||
| 		<div class="path" @contextmenu.prevent.stop="() => {}"> | 		<div class="path" @contextmenu.prevent.stop="() => {}"> | ||||||
| 			<x-nav-folder :class="{ current: folder == null }"/> | 			<x-nav-folder :class="{ current: folder == null }"/> | ||||||
| 			<template v-for="folder in hierarchyFolders"> | 			<template v-for="folder in hierarchyFolders"> | ||||||
| 				<span class="separator">%fa:angle-right%</span> | 				<span class="separator"><fa icon="angle-right"/></span> | ||||||
| 				<x-nav-folder :folder="folder" :key="folder.id"/> | 				<x-nav-folder :folder="folder" :key="folder.id"/> | ||||||
| 			</template> | 			</template> | ||||||
| 			<span class="separator" v-if="folder != null">%fa:angle-right%</span> | 			<span class="separator" v-if="folder != null"><fa icon="angle-right"/></span> | ||||||
| 			<span class="folder current" v-if="folder != null">{{ folder.name }}</span> | 			<span class="folder current" v-if="folder != null">{{ folder.name }}</span> | ||||||
| 		</div> | 		</div> | ||||||
| 		<!-- | 		<!-- | ||||||
| @@ -138,17 +138,17 @@ export default Vue.extend({ | |||||||
| 			contextmenu((this as any).os)(e, [{ | 			contextmenu((this as any).os)(e, [{ | ||||||
| 				type: 'item', | 				type: 'item', | ||||||
| 				text: '%i18n:@contextmenu.create-folder%', | 				text: '%i18n:@contextmenu.create-folder%', | ||||||
| 				icon: '%fa:R folder%', | 				icon: ['far', 'folder'], | ||||||
| 				action: this.createFolder | 				action: this.createFolder | ||||||
| 			}, { | 			}, { | ||||||
| 				type: 'item', | 				type: 'item', | ||||||
| 				text: '%i18n:@contextmenu.upload%', | 				text: '%i18n:@contextmenu.upload%', | ||||||
| 				icon: '%fa:upload%', | 				icon: 'upload', | ||||||
| 				action: this.selectLocalFile | 				action: this.selectLocalFile | ||||||
| 			}, { | 			}, { | ||||||
| 				type: 'item', | 				type: 'item', | ||||||
| 				text: '%i18n:@contextmenu.url-upload%', | 				text: '%i18n:@contextmenu.url-upload%', | ||||||
| 				icon: '%fa:cloud-upload-alt%', | 				icon: 'cloud-upload-alt', | ||||||
| 				action: this.urlUpload | 				action: this.urlUpload | ||||||
| 			}]); | 			}]); | ||||||
| 		}, | 		}, | ||||||
| @@ -313,7 +313,7 @@ export default Vue.extend({ | |||||||
| 					switch (err) { | 					switch (err) { | ||||||
| 						case 'detected-circular-definition': | 						case 'detected-circular-definition': | ||||||
| 							(this as any).apis.dialog({ | 							(this as any).apis.dialog({ | ||||||
| 								title: '%fa:exclamation-triangle%%i18n:@unable-to-process%', | 								title: '<fa icon="exclamation-triangle"/>%i18n:@unable-to-process%', | ||||||
| 								text: '%i18n:@circular-reference-detected%', | 								text: '%i18n:@circular-reference-detected%', | ||||||
| 								actions: [{ | 								actions: [{ | ||||||
| 									text: '%i18n:common.ok%' | 									text: '%i18n:common.ok%' | ||||||
| @@ -343,7 +343,7 @@ export default Vue.extend({ | |||||||
| 				}); | 				}); | ||||||
|  |  | ||||||
| 				(this as any).apis.dialog({ | 				(this as any).apis.dialog({ | ||||||
| 					title: '%fa:check%%i18n:@url-upload-requested%', | 					title: '<fa icon="check"/>%i18n:@url-upload-requested%', | ||||||
| 					text: '%i18n:@may-take-time%', | 					text: '%i18n:@may-take-time%', | ||||||
| 					actions: [{ | 					actions: [{ | ||||||
| 						text: '%i18n:common.ok%' | 						text: '%i18n:common.ok%' | ||||||
| @@ -613,9 +613,6 @@ export default Vue.extend({ | |||||||
| 				line-height 38px | 				line-height 38px | ||||||
| 				cursor pointer | 				cursor pointer | ||||||
|  |  | ||||||
| 				i |  | ||||||
| 					margin-right 4px |  | ||||||
|  |  | ||||||
| 				* | 				* | ||||||
| 					pointer-events none | 					pointer-events none | ||||||
|  |  | ||||||
| @@ -635,7 +632,7 @@ export default Vue.extend({ | |||||||
| 					opacity 0.5 | 					opacity 0.5 | ||||||
| 					cursor default | 					cursor default | ||||||
|  |  | ||||||
| 					> [data-fa] | 					> [data-icon] | ||||||
| 						margin 0 | 						margin 0 | ||||||
|  |  | ||||||
| 		> .search | 		> .search | ||||||
|   | |||||||
| @@ -5,13 +5,13 @@ | |||||||
| 	:disabled="wait" | 	:disabled="wait" | ||||||
| > | > | ||||||
| 	<template v-if="!wait"> | 	<template v-if="!wait"> | ||||||
| 		<template v-if="u.hasPendingFollowRequestFromYou && u.isLocked">%fa:hourglass-half%<template v-if="size == 'big'"> %i18n:@request-pending%</template></template> | 		<template v-if="u.hasPendingFollowRequestFromYou && u.isLocked"><fa icon="hourglass-half"/><template v-if="size == 'big'"> %i18n:@request-pending%</template></template> | ||||||
| 		<template v-else-if="u.hasPendingFollowRequestFromYou && !u.isLocked">%fa:hourglass-start%<template v-if="size == 'big'"> %i18n:@follow-processing%</template></template> | 		<template v-else-if="u.hasPendingFollowRequestFromYou && !u.isLocked"><fa icon="hourglass-start"/><template v-if="size == 'big'"> %i18n:@follow-processing%</template></template> | ||||||
| 		<template v-else-if="u.isFollowing">%fa:minus%<template v-if="size == 'big'"> %i18n:@following%</template></template> | 		<template v-else-if="u.isFollowing"><fa icon="minus"/><template v-if="size == 'big'"> %i18n:@following%</template></template> | ||||||
| 		<template v-else-if="!u.isFollowing && u.isLocked">%fa:plus%<template v-if="size == 'big'"> %i18n:@follow-request%</template></template> | 		<template v-else-if="!u.isFollowing && u.isLocked"><fa icon="plus"/><template v-if="size == 'big'"> %i18n:@follow-request%</template></template> | ||||||
| 		<template v-else-if="!u.isFollowing && !u.isLocked">%fa:plus%<template v-if="size == 'big'"> %i18n:@follow%</template></template> | 		<template v-else-if="!u.isFollowing && !u.isLocked"><fa icon="plus"/><template v-if="size == 'big'"> %i18n:@follow%</template></template> | ||||||
| 	</template> | 	</template> | ||||||
| 	<template v-else>%fa:spinner .pulse .fw%</template> | 	<template v-else><fa icon="spinner .pulse" fixed-width/></template> | ||||||
| </button> | </button> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -11,9 +11,9 @@ | |||||||
| 		</div> | 		</div> | ||||||
| 	</div> | 	</div> | ||||||
| 	<p class="empty" v-if="!fetching && users.length == 0">%i18n:@empty%</p> | 	<p class="empty" v-if="!fetching && users.length == 0">%i18n:@empty%</p> | ||||||
| 	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@fetching%<mk-ellipsis/></p> | 	<p class="fetching" v-if="fetching"><fa icon="spinner .pulse" fixed-width/>%i18n:@fetching%<mk-ellipsis/></p> | ||||||
| 	<a class="refresh" @click="refresh">%i18n:@refresh%</a> | 	<a class="refresh" @click="refresh">%i18n:@refresh%</a> | ||||||
| 	<button class="close" @click="destroyDom()" title="%i18n:@close%">%fa:times%</button> | 	<button class="close" @click="destroyDom()" title="%i18n:@close%"><fa icon="times"/></button> | ||||||
| </div> | </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| @@ -124,7 +124,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 | ||||||
|  |  | ||||||
| 	> .refresh | 	> .refresh | ||||||
| @@ -155,7 +155,7 @@ export default Vue.extend({ | |||||||
| 		&:active | 		&:active | ||||||
| 			color #222 | 			color #222 | ||||||
|  |  | ||||||
| 		> [data-fa] | 		> [data-icon] | ||||||
| 			padding 14px | 			padding 14px | ||||||
|  |  | ||||||
| </style> | </style> | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| <template> | <template> | ||||||
| <mk-window ref="window" width="500px" height="560px" :popout-url="popout" @closed="destroyDom"> | <mk-window ref="window" width="500px" height="560px" :popout-url="popout" @closed="destroyDom"> | ||||||
| 	<span slot="header" :class="$style.header">%fa:gamepad%%i18n:@game%</span> | 	<span slot="header" :class="$style.header"><fa icon="gamepad"/>%i18n:@game%</span> | ||||||
| 	<mk-reversi :class="$style.content" @gamed="g => game = g"/> | 	<mk-reversi :class="$style.content" @gamed="g => game = g"/> | ||||||
| </mk-window> | </mk-window> | ||||||
| </template> | </template> | ||||||
| @@ -27,7 +27,7 @@ export default Vue.extend({ | |||||||
|  |  | ||||||
| <style lang="stylus" module> | <style lang="stylus" module> | ||||||
| .header | .header | ||||||
| 	> [data-fa] | 	> [data-icon] | ||||||
| 		margin-right 4px | 		margin-right 4px | ||||||
|  |  | ||||||
| .content | .content | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| <template> | <template> | ||||||
| <div class="mk-home" :data-customize="customize"> | <div class="mk-home" :data-customize="customize"> | ||||||
| 	<div class="customize" v-if="customize"> | 	<div class="customize" v-if="customize"> | ||||||
| 		<router-link to="/">%fa:check%%i18n:@done%</router-link> | 		<router-link to="/"><fa icon="check"/>%i18n:@done%</router-link> | ||||||
| 		<div> | 		<div> | ||||||
| 			<div class="adder"> | 			<div class="adder"> | ||||||
| 				<p>%i18n:@add-widget%</p> | 				<p>%i18n:@add-widget%</p> | ||||||
| @@ -185,7 +185,7 @@ export default Vue.extend({ | |||||||
| 	methods: { | 	methods: { | ||||||
| 		hint() { | 		hint() { | ||||||
| 			(this as any).apis.dialog({ | 			(this as any).apis.dialog({ | ||||||
| 				title: '%fa:info-circle%%i18n:common.customization-tips.title%', | 				title: '<fa icon="info-circle"/>%i18n:common.customization-tips.title%', | ||||||
| 				text: '<p>%i18n:common.customization-tips.paragraph1%</p>' + | 				text: '<p>%i18n:common.customization-tips.paragraph1%</p>' + | ||||||
| 					'<p>%i18n:common.customization-tips.paragraph2%</p>' + | 					'<p>%i18n:common.customization-tips.paragraph2%</p>' + | ||||||
| 					'<p>%i18n:common.customization-tips.paragraph3%</p>' + | 					'<p>%i18n:common.customization-tips.paragraph3%</p>' + | ||||||
| @@ -299,7 +299,7 @@ export default Vue.extend({ | |||||||
| 				background var(--primaryDarken10) | 				background var(--primaryDarken10) | ||||||
| 				transition background 0s ease | 				transition background 0s ease | ||||||
|  |  | ||||||
| 			> [data-fa] | 			> [data-icon] | ||||||
| 				margin-right 8px | 				margin-right 8px | ||||||
|  |  | ||||||
| 		> div | 		> div | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| <template> | <template> | ||||||
| <mk-window ref="window" is-modal width="500px" @before-close="beforeClose" @closed="destroyDom"> | <mk-window ref="window" is-modal width="500px" @before-close="beforeClose" @closed="destroyDom"> | ||||||
| 	<span slot="header" :class="$style.header"> | 	<span slot="header" :class="$style.header"> | ||||||
| 		%fa:i-cursor%{{ title }} | 		<fa icon="i-cursor"/>{{ title }} | ||||||
| 	</span> | 	</span> | ||||||
|  |  | ||||||
| 	<div :class="$style.body"> | 	<div :class="$style.body"> | ||||||
| @@ -76,10 +76,8 @@ export default Vue.extend({ | |||||||
|  |  | ||||||
|  |  | ||||||
| <style lang="stylus" module> | <style lang="stylus" module> | ||||||
|  |  | ||||||
|  |  | ||||||
| .header | .header | ||||||
| 	> [data-fa] | 	> [data-icon] | ||||||
| 		margin-right 4px | 		margin-right 4px | ||||||
|  |  | ||||||
| .body | .body | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| <template> | <template> | ||||||
| <div class="ldwbgwstjsdgcjruamauqdrffetqudry" v-if="image.isSensitive && hide && !$store.state.device.alwaysShowNsfw" @click="hide = false"> | <div class="ldwbgwstjsdgcjruamauqdrffetqudry" v-if="image.isSensitive && hide && !$store.state.device.alwaysShowNsfw" @click="hide = false"> | ||||||
| 	<div> | 	<div> | ||||||
| 		<b>%fa:exclamation-triangle% %i18n:@sensitive%</b> | 		<b><fa icon="exclamation-triangle"/> %i18n:@sensitive%</b> | ||||||
| 		<span>%i18n:@click-to-show%</span> | 		<span>%i18n:@click-to-show%</span> | ||||||
| 	</div> | 	</div> | ||||||
| </div> | </div> | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| <template> | <template> | ||||||
| <div class="uofhebxjdgksfmltszlxurtjnjjsvioh" v-if="video.isSensitive && hide" @click="hide = false"> | <div class="uofhebxjdgksfmltszlxurtjnjjsvioh" v-if="video.isSensitive && hide" @click="hide = false"> | ||||||
| 	<div> | 	<div> | ||||||
| 		<b>%fa:exclamation-triangle% %i18n:@sensitive%</b> | 		<b><fa icon="exclamation-triangle"/> %i18n:@sensitive%</b> | ||||||
| 		<span>%i18n:@click-to-show%</span> | 		<span>%i18n:@click-to-show%</span> | ||||||
| 	</div> | 	</div> | ||||||
| </div> | </div> | ||||||
| @@ -12,7 +12,7 @@ | |||||||
| 		@click.prevent="onClick" | 		@click.prevent="onClick" | ||||||
| 		:title="video.name" | 		:title="video.name" | ||||||
| 	> | 	> | ||||||
| 		%fa:R play-circle% | 		<fa :icon="['far', 'play-circle']"/> | ||||||
| 	</a> | 	</a> | ||||||
| </div> | </div> | ||||||
| </template> | </template> | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| <template> | <template> | ||||||
| <mk-window ref="window" width="500px" height="560px" :popout-url="popout" @closed="destroyDom"> | <mk-window ref="window" width="500px" height="560px" :popout-url="popout" @closed="destroyDom"> | ||||||
| 	<span slot="header" :class="$style.header">%fa:comments%%i18n:@title% {{ user | userName }}</span> | 	<span slot="header" :class="$style.header"><fa icon="comments"/>%i18n:@title% {{ user | userName }}</span> | ||||||
| 	<mk-messaging-room :user="user" :class="$style.content"/> | 	<mk-messaging-room :user="user" :class="$style.content"/> | ||||||
| </mk-window> | </mk-window> | ||||||
| </template> | </template> | ||||||
| @@ -22,7 +22,7 @@ export default Vue.extend({ | |||||||
|  |  | ||||||
| <style lang="stylus" module> | <style lang="stylus" module> | ||||||
| .header | .header | ||||||
| 	> [data-fa] | 	> [data-icon] | ||||||
| 		margin-right 4px | 		margin-right 4px | ||||||
|  |  | ||||||
| .content | .content | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| <template> | <template> | ||||||
| <mk-window ref="window" width="500px" height="560px" @closed="destroyDom"> | <mk-window ref="window" width="500px" height="560px" @closed="destroyDom"> | ||||||
| 	<span slot="header" :class="$style.header">%fa:comments%%i18n:@title%</span> | 	<span slot="header" :class="$style.header"><fa icon="comments"/>%i18n:@title%</span> | ||||||
| 	<mk-messaging :class="$style.content" @navigate="navigate"/> | 	<mk-messaging :class="$style.content" @navigate="navigate"/> | ||||||
| </mk-window> | </mk-window> | ||||||
| </template> | </template> | ||||||
| @@ -22,7 +22,7 @@ export default Vue.extend({ | |||||||
|  |  | ||||||
| <style lang="stylus" module> | <style lang="stylus" module> | ||||||
| .header | .header | ||||||
| 	> [data-fa] | 	> [data-icon] | ||||||
| 		margin-right 4px | 		margin-right 4px | ||||||
|  |  | ||||||
| .content | .content | ||||||
|   | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user