Compare commits

..

116 Commits

Author SHA1 Message Date
9dd21a19ff 10.44.1 2018-11-07 19:49:46 +09:00
a8d05cba5a Fix #3149 2018-11-07 19:43:21 +09:00
f5ddfb29f2 10.44.0 2018-11-07 13:16:29 +09:00
ba228a6b10 Clean up 2018-11-07 13:15:09 +09:00
cb6f390fb6 GitHub / Twitter連携の設定をDBに保存するように 2018-11-07 13:14:52 +09:00
5675ecead9 Fix 2018-11-07 12:30:56 +09:00
001bb7bbcd インスタンスの対象言語の設定を実装 2018-11-07 12:28:53 +09:00
1585bb12cf 🎨 2018-11-07 12:17:57 +09:00
26b47c18fd [Client] Fix #2737 2018-11-07 12:15:28 +09:00
665fa7f2aa [API] Improve drive/files/upload_from_url 2018-11-07 12:12:43 +09:00
0068dc30d3 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2018-11-07 12:09:33 +09:00
8f39655fef Fix bug 2018-11-07 12:09:24 +09:00
b1a4fc03bc Update @types/koa-router requirement from 7.0.32 to 7.0.33 (#3147)
Updates the requirements on [@types/koa-router](https://github.com/DefinitelyTyped/DefinitelyTyped) to permit the latest version.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-07 09:24:13 +09:00
05d20f1044 Update @types/request requirement from 2.48.0 to 2.48.1 (#3146)
Updates the requirements on [@types/request](https://github.com/DefinitelyTyped/DefinitelyTyped) to permit the latest version.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-07 09:24:04 +09:00
66a90b3fb1 Update qrcode requirement from 1.3.0 to 1.3.2 (#3145)
Updates the requirements on [qrcode](https://github.com/soldair/node-qrcode) to permit the latest version.
- [Release notes](https://github.com/soldair/node-qrcode/releases)
- [Commits](https://github.com/soldair/node-qrcode/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-07 09:23:47 +09:00
826d9d9fdf Update typescript requirement from 3.1.5 to 3.1.6 (#3144)
Updates the requirements on [typescript](https://github.com/Microsoft/TypeScript) to permit the latest version.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](https://github.com/Microsoft/TypeScript/commits/v3.1.6)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2018-11-07 09:23:38 +09:00
4a9a61f108 10.43.1 2018-11-07 03:57:08 +09:00
b72d15b56c [Client] Improve usability 2018-11-07 03:48:58 +09:00
8c68992594 Fix deploy fails on CircleCI 2018-11-07 02:06:32 +09:00
c052028fc3 10.43.0 2018-11-07 01:19:03 +09:00
c46fbcf345 Clean up 2018-11-07 01:18:21 +09:00
06b66f0209 メンテナ情報をDBに保存するように 2018-11-07 01:12:26 +09:00
2de48110bb ghostの設定をDBに保存するように 2018-11-07 00:44:56 +09:00
87d4452d19 Clean up 2018-11-07 00:16:32 +09:00
328fc64ca9 🎨 2018-11-07 00:16:08 +09:00
a6f8327aa2 reCAPTCHAの設定をDBに保存するように 2018-11-07 00:08:21 +09:00
d5ab6b41c9 10.42.2 2018-11-06 20:54:15 +09:00
ffdd0b7de7 [API] 文字列での真理値表現に対応
multipart/formdata では文字列しか送れないっぽい?
2018-11-06 20:53:50 +09:00
1808eb6eee 10.42.1 2018-11-06 20:49:03 +09:00
438563b505 [API] Fix bug 2018-11-06 20:47:56 +09:00
92dfcdad57 Fix #3141 2018-11-06 20:47:07 +09:00
c178cfabfa 10.42.0 2018-11-06 15:52:28 +09:00
260e4c955d 🎨 2018-11-06 15:51:18 +09:00
0c46f5ce70 Clean up 2018-11-06 15:51:05 +09:00
6d67cd07a0 [Client] Use dynamic import to reduce bundle size 2018-11-06 15:37:41 +09:00
fb8af53751 [Client] Improve usability & Refactoring 2018-11-06 15:08:22 +09:00
37999f4af7 [API] Implement notes/watching/ 2018-11-06 14:58:20 +09:00
3b6ab327c1 Twemojiで合字に対応 (#3140)
* Twemojiで合字に対応

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

* not explicitly close on end

* resolve on stream finish

* remove unnecessary code

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

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

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

* Rename

* Clean up

* Clean up

* wip

* wip

* Enable tree shaking

* ✌️

* ✌️

* wip

* wip

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

* Add `npm prune` command

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

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

From commit dca110ebaa.

* Re-separate commits

From commit 9719387bee.
2018-11-05 11:57:17 +09:00
9719387bee Re-separate commits 2018-11-05 11:51:14 +09:00
dca110ebaa Separate commits
Flash Back 90's
2018-11-05 11:39:13 +09:00
136f23c7ad Merge branch 'develop' into twemoji 2018-11-05 11:21:34 +09:00
0963e6d6e1 Use Twemoji 2018-11-05 11:19:40 +09:00
712802e682 10.38.7 2018-11-05 11:11:23 +09:00
abe99c3c73 Update locales/ja-JP.yml 2018-11-05 11:10:02 +09:00
d7a3b71028 投稿の最大文字数情報を設定ファイルではなくDBに保存するように 2018-11-05 11:09:05 +09:00
10c434f24a Remove Travis
Closes #3109
2018-11-05 10:52:07 +09:00
fe46c53ea6 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2018-11-05 10:48:51 +09:00
cdd123dfd3 [doc] specify node version 2018-11-05 10:48:40 +09:00
a1a3ee44b5 Implement /api/v1/custom_emojis (#3116) 2018-11-05 10:45:57 +09:00
4e7fbd8967 Implement /api/v1/custom_emojis 2018-11-05 10:42:46 +09:00
a86c419f95 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2018-11-05 10:40:15 +09:00
e3ec0ad97e [Client] Improve admin panel usability 2018-11-05 10:40:01 +09:00
75791981ce Fix #3115 2018-11-05 10:34:53 +09:00
e813fe16b9 [API] Better validation of admin/emoji/add 2018-11-05 10:33:49 +09:00
42ac7b954d Improve admin panel usability 2018-11-05 10:32:45 +09:00
c1bbf5dab6 [Client] Fix error 2018-11-05 10:29:57 +09:00
e16dc2a910 Update README.md (#3112) 2018-11-05 01:57:08 +09:00
260 changed files with 2668 additions and 1875 deletions

View File

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

View File

@ -1,6 +1,3 @@
maintainer:
name: syuilo
url: 'https://syuilo.com'
url: 'http://misskey.local'
port: 80
mongodb:

View File

@ -1,6 +1,3 @@
maintainer:
name: syuilo
url: 'https://syuilo.com'
url: 'http://misskey.local'
port: 80
mongodb:

View File

@ -1,10 +1,3 @@
maintainer:
name: example-maitainer-name # Your name
url: http://example.com/ # Your contact (http or mailto)
repository_url: https://github.com/syuilo/misskey # Repository URL
feedback_url: https://github.com/syuilo/misskey/issues # Feedback URL (e.g. github issue)
# Final accessible URL seen by a user.
url: https://example.tld/
@ -57,21 +50,6 @@ mongodb:
user: example-misskey-user
pass: example-misskey-pass
# Drive capacity of a local user (MB)
localDriveCapacityMb: 256
# Drive capacity of a remote user (MB)
remoteDriveCapacityMb: 8
# If enabled:
# Server will not cache remote files (Using direct link instead).
# You can save your storage.
#
# NOTE:
# * Users cannot see remote images when they turn off "Show media from a remote server" setting.
# * Since thumbnails are not provided, traffic increases.
preventCacheRemoteFiles: false
drive:
storage: 'db'
@ -110,6 +88,10 @@ drive:
# accessKey: XXX
# secretKey: YYY
# If enabled:
# The first account created is automatically marked as Admin.
autoAdmin: true
#
# Below settings are optional
#
@ -126,11 +108,6 @@ drive:
# port: 9200
# pass: null
# reCAPTCHA
#recaptcha:
# site_key: example-site-key
# secret_key: example-secret-key
# ServiceWorker
#sw:
# # Public key of VAPID
@ -139,23 +116,6 @@ drive:
# # Private key of VAPID
# private_key: example-sw-private-key
# Twitter integration
# You need to set the oauth callback url as : https://<your-misskey-instance>/api/tw/cb
#twitter:
# consumer_key: example-twitter-consumer-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 account is an account used for the purpose of delegating
# followers when putting users in the list.
#ghost: user-id-of-your-ghost-account
# Clustering
#clusterLimit: 1
@ -167,6 +127,3 @@ drive:
# external: true
# engine: http://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}
# timeout: 300000
# Max allowed note text length in charactors
maxNoteTextLength: 1000

View File

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

View File

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

View File

@ -4,7 +4,6 @@
================================================================
[![CircleCI](https://circleci.com/gh/syuilo/misskey.svg?style=svg)](https://circleci.com/gh/syuilo/misskey)
[![][travis-badge]][travis-link]
[![][dependencies-badge]][dependencies-link]
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
@ -44,7 +43,7 @@ Easiest way to tell your emotions. Misskey allows you to add various type of rea
<h3 align="left">Interface</h3>
<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>
---
@ -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-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-badge]: https://img.shields.io/david/syuilo/misskey.svg?style=flat-square

View File

@ -22,7 +22,7 @@ adduser --disabled-password --disabled-login misskey
Please install and setup these softwares:
#### Dependencies :package:
* **[Node.js](https://nodejs.org/en/)**
* **[Node.js](https://nodejs.org/en/)** >= 10.0.0
* **[MongoDB](https://www.mongodb.com/)** >= 3.6
##### Optional
@ -47,11 +47,6 @@ In root :
4. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` Checkout to the [latest release](https://github.com/syuilo/misskey/releases/latest)
5. `npm install` Install misskey dependencies.
*(optional)* reCAPTCHA tokens
----------------------------------------------------------------
If you want to enable reCAPTCHA, you need to generate reCAPTCHA tokens:
Please visit https://www.google.com/recaptcha/intro/ and generate keys.
*(optional)* Generating VAPID keys
----------------------------------------------------------------
If you want to enable ServiceWorker, you need to generate VAPID keys:
@ -62,13 +57,6 @@ npm install web-push -g
web-push generate-vapid-keys
```
*(optional)* Create a twitter application
----------------------------------------------------------------
If you want to enable the twitter integration, you need to create a twitter app at [https://developer.twitter.com/en/apply/user](https://developer.twitter.com/en/apply/user).
In the app you need to set the oauth callback url as : https://misskey-instance/api/tw/cb
*5.* Make configuration file
----------------------------------------------------------------
1. `cp .config/example.yml .config/default.yml` Copy the `.config/example.yml` and rename it to `default.yml`.

View File

@ -22,7 +22,7 @@ adduser --disabled-password --disabled-login misskey
これらのソフトウェアをインストール・設定してください:
#### 依存関係 :package:
* **[Node.js](https://nodejs.org/en/)**
* **[Node.js](https://nodejs.org/en/)** (10.0.0以上)
* **[MongoDB](https://www.mongodb.com/)** (3.6以上)
##### オプション
@ -53,11 +53,6 @@ adduser --disabled-password --disabled-login misskey
4. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` [最新のリリース](https://github.com/syuilo/misskey/releases/latest)を確認
5. `npm install` Misskeyの依存パッケージをインストール
*(オプション)* reCAPTCHAトークン
----------------------------------------------------------------
reCAPTCHAを有効にする場合、reCAPTCHAトークンを取得する必要があります。
https://www.google.com/recaptcha/intro/ にアクセスしてトークンを取得してください。
*(オプション)* VAPIDキーペアの生成
----------------------------------------------------------------
ServiceWorkerを有効にする場合、VAPIDキーペアを生成する必要があります:

View File

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

View File

@ -131,6 +131,7 @@ common:
show-full-acct: "ユーザー名のホストを省略しない"
reduce-motion: "UIの動きを減らす"
this-setting-is-this-device-only: "このデバイスのみ"
use-os-default-emojis: "OS標準の絵文字を使用"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
@ -946,6 +947,7 @@ common/views/components/api-settings.vue:
title: 'APIコンソール'
endpoint: 'エンドポイント'
parameter: 'パラメータ'
credential-info: "「i」パラメータは自動で付与されます。"
send: '送信'
sending: '応答待ち'
response: '結果'
@ -1077,10 +1079,43 @@ admin/views/instance.vue:
instance-name: "インスタンス名"
instance-description: "インスタンスの紹介"
banner-url: "バナー画像URL"
disableRegistration: "ユーザー登録の受付を停止する"
disableLocalTimeline: "ローカルタイムラインを無効にする"
languages: "インスタンスの対象言語"
languages-desc: "スペースで区切って複数設定できます。"
maintainer-config: "管理者情報"
maintainer-name: "管理者名"
maintainer-email: "管理者の連絡先"
drive-config: "ドライブの設定"
cache-remote-files: "リモートのファイルをキャッシュする"
cache-remote-files-desc: "この設定を無効にすると、リモートファイルをキャッシュせず直リンクするようになります。そのためサーバーのストレージを節約できますが、プライバシー設定で直リンクを無効にしているユーザーにはファイルが見えなくなったり、サムネイルが生成されないので通信量が増加します。通常はこの設定をオンにしておくことをおすすめします。"
local-drive-capacity-mb: "ローカルユーザーひとりあたりのドライブ容量"
remote-drive-capacity-mb: "リモートユーザーひとりあたりのドライブ容量"
mb: "メガバイト単位"
recaptcha-config: "reCAPTCHAの設定"
recaptcha-info: "reCAPTCHAを有効にする場合、reCAPTCHAトークンを取得する必要があります。https://www.google.com/recaptcha/intro/ にアクセスしてトークンを取得してください。"
enable-recaptcha: "reCAPTCHAを有効にする"
recaptcha-site-key: "reCAPTCHA site key"
recaptcha-secret-key: "reCAPTCHA secret key"
twitter-integration-config: "Twitter連携の設定"
twitter-integration-info: "コールバックURLは /api/tw/cb に設定します。"
enable-twitter-integration: "Twitter連携を有効にする"
twitter-integration-consumer-key: "Consumer key"
twitter-integration-consumer-secret: "Consumer secret"
github-integration-config: "GitHub連携の設定"
github-integration-info: "コールバックURLは /api/gh/cb に設定します。"
enable-github-integration: "GitHub連携を有効にする"
github-integration-client-id: "Client ID"
github-integration-client-secret: "Client secret"
proxy-account-config: "プロキシアカウントの設定"
proxy-account-info: "プロキシアカウントは、特定の条件下でユーザーのリモートフォローを代行するアカウントです。例えば、ユーザーがリモートユーザーをリストに入れたとき、リストに入れられたユーザーを誰もフォローしていないとアクティビティがサーバーに配達されないため、代わりにプロキシアカウントがフォローするようにします。"
proxy-account-username: "プロキシアカウントのユーザー名"
proxy-account-username-desc: "プロキシとして使用するアカウントのユーザー名を指定してください。"
proxy-account-warn: "アカウントは自動で作られないため、そのユーザー名のアカウントを予め作成しておく必要があります。"
max-note-text-length: "投稿の最大文字数"
disable-registration: "ユーザー登録の受付を停止する"
disable-local-timeline: "ローカルタイムラインを無効にする"
invite: "招待"
save: "保存"
saved: "保存しました"
admin/views/charts.vue:
title: "チャート"
@ -1132,10 +1167,15 @@ admin/views/emoji.vue:
url: "絵文字画像URL"
add: "追加"
info: "50KB以下のPNG画像をおすすめします。"
added: "絵文字を登録しました"
emojis:
title: "絵文字一覧"
update: "更新"
remove: "削除"
updated: "更新しました"
remove-emoji:
are-you-sure: "「$1」を削除しますか"
removed: "削除しました"
admin/views/announcements.vue:
announcements: "お知らせ"
@ -1144,6 +1184,10 @@ admin/views/announcements.vue:
add: "追加"
title: "タイトル"
text: "内容"
saved: "保存しました"
_remove:
are-you-sure: "「$1」を削除しますか"
removed: "削除しました"
admin/views/hashtags.vue:
hided-tags: "Hidden Tags"

View File

@ -1,8 +1,8 @@
{
"name": "misskey",
"author": "syuilo <i@syuilo.com>",
"version": "10.38.6",
"clientVersion": "1.0.11516",
"version": "10.44.1",
"clientVersion": "1.0.11630",
"codename": "nighthike",
"main": "./built/index.js",
"private": true,
@ -20,10 +20,11 @@
"format": "gulp format"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "1.2.6",
"@fortawesome/free-brands-svg-icons": "5.4.1",
"@fortawesome/free-regular-svg-icons": "5.4.1",
"@fortawesome/free-solid-svg-icons": "5.4.1",
"@fortawesome/fontawesome-svg-core": "1.2.8",
"@fortawesome/free-brands-svg-icons": "5.5.0",
"@fortawesome/free-regular-svg-icons": "5.5.0",
"@fortawesome/free-solid-svg-icons": "5.5.0",
"@fortawesome/vue-fontawesome": "0.1.2",
"@koa/cors": "2.2.2",
"@prezzemolo/rap": "0.1.2",
"@prezzemolo/zip": "0.0.3",
@ -52,7 +53,7 @@
"@types/koa-logger": "3.1.1",
"@types/koa-mount": "3.0.1",
"@types/koa-multer": "1.0.0",
"@types/koa-router": "7.0.32",
"@types/koa-router": "7.0.33",
"@types/koa-send": "4.1.1",
"@types/koa-views": "2.0.3",
"@types/koa__cors": "2.2.3",
@ -68,7 +69,7 @@
"@types/qrcode": "1.3.0",
"@types/ratelimiter": "2.1.28",
"@types/redis": "2.8.7",
"@types/request": "2.48.0",
"@types/request": "2.48.1",
"@types/request-promise-native": "1.0.15",
"@types/rimraf": "2.0.2",
"@types/seedrandom": "2.4.27",
@ -112,7 +113,7 @@
"eslint-plugin-vue": "4.7.1",
"eventemitter3": "3.1.0",
"file-loader": "2.0.0",
"file-type": "10.3.0",
"file-type": "10.4.0",
"fuckadblock": "3.2.1",
"gulp": "3.9.1",
"gulp-cssnano": "2.1.3",
@ -173,7 +174,7 @@
"promise-sequential": "1.1.1",
"pug": "2.0.3",
"punycode": "2.1.1",
"qrcode": "1.3.0",
"qrcode": "1.3.2",
"ratelimiter": "3.2.0",
"recaptcha-promise": "0.1.3",
"reconnecting-websocket": "4.1.10",
@ -204,7 +205,7 @@
"ts-loader": "5.3.0",
"ts-node": "7.0.1",
"tslint": "5.10.0",
"typescript": "3.1.5",
"typescript": "3.1.6",
"typescript-eslint-parser": "20.1.1",
"uglify-es": "3.3.9",
"url-loader": "1.1.2",
@ -215,7 +216,6 @@
"vue-content-loading": "1.5.3",
"vue-cropperjs": "2.2.2",
"vue-js-modal": "1.3.26",
"vue-json-tree-view": "2.1.4",
"vue-loader": "15.4.2",
"vue-router": "3.0.1",
"vue-style-loader": "4.1.2",
@ -228,7 +228,7 @@
"vuex-persistedstate": "2.5.4",
"web-push": "3.3.3",
"webfinger.js": "2.6.6",
"webpack": "4.23.1",
"webpack": "4.25.1",
"webpack-cli": "3.1.2",
"websocket": "1.0.28",
"ws": "6.1.0",

View File

@ -1,7 +1,7 @@
<template>
<div class="cdeuzmsthagexbkpofbmatmugjuvogfb">
<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">
<ui-input v-model="announcement.title" @change="save">
<span>%i18n:@title%</span>
@ -10,12 +10,12 @@
<span>%i18n:@text%</span>
</ui-textarea>
<ui-horizon-group>
<ui-button @click="save">%fa:save R% %i18n:@save%</ui-button>
<ui-button @click="remove(i)">%fa:trash-alt R% %i18n:@remove%</ui-button>
<ui-button @click="save()"><fa :icon="['far', 'save']"/> %i18n:@save%</ui-button>
<ui-button @click="remove(i)"><fa :icon="['far', 'trash-alt']"/> %i18n:@remove%</ui-button>
</ui-horizon-group>
</section>
<section>
<ui-button @click="add">%fa:plus% %i18n:@add%</ui-button>
<ui-button @click="add"><fa icon="plus"/> %i18n:@add%</ui-button>
</section>
</ui-card>
</div>
@ -46,17 +46,36 @@ export default Vue.extend({
},
remove(i) {
this.announcements = this.announcements.filter((_, j) => j !== i);
this.save();
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.save(true);
this.$swal({
type: 'success',
text: '%i18n:@_remove.removed%'
});
});
},
save() {
save(silent) {
(this as any).api('admin/update-meta', {
broadcasts: this.announcements
}).then(() => {
//(this as any).os.apis.dialog({ text: `Saved` });
if (!silent) {
this.$swal({
type: 'success',
text: '%i18n:@saved%'
});
}
}).catch(e => {
//(this as any).os.apis.dialog({ text: `Failed ${e}` });
this.$swal({
type: 'error',
text: e
});
});
}
}

View File

@ -3,10 +3,10 @@
<table>
<thead>
<tr>
<th>%fa:exchange-alt% In/Out</th>
<th>%fa:server% Host</th>
<th>%fa:bolt% Activity</th>
<th>%fa:user% Actor</th>
<th><fa icon="exchange-alt"/> In/Out</th>
<th><fa icon="server"/> Host</th>
<th><fa icon="bolt"/> Activity</th>
<th><fa icon="user"/> Actor</th>
</tr>
</thead>
<tbody>

View File

@ -1,7 +1,7 @@
<template>
<div class="qvgidhudpqhjttdhxubzuyrhyzgslujw">
<header>
<b>%fa:chart-bar R% %i18n:@title%:</b>
<b><fa :icon="['far', 'chart-bar']"/> %i18n:@title%:</b>
<select v-model="src">
<optgroup label="%i18n:@federation%">
<option value="federation-instances">%i18n:@charts.federation-instances%</option>
@ -274,12 +274,15 @@ export default Vue.extend({
return {
series: [{
name: 'Combined',
type: 'line',
data: this.format(sum(this.stats.notes.local.total, this.stats.notes.remote.total))
}, {
name: 'Local',
type: 'area',
data: this.format(this.stats.notes.local.total)
}, {
name: 'Remote',
type: 'area',
data: this.format(this.stats.notes.remote.total)
}]
};
@ -289,18 +292,21 @@ export default Vue.extend({
return {
series: [{
name: 'Combined',
type: 'line',
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))
)
}, {
name: 'Local',
type: 'area',
data: this.format(total
? this.stats.users.local.total
: sum(this.stats.users.local.inc, negate(this.stats.users.local.dec))
)
}, {
name: 'Remote',
type: 'area',
data: this.format(total
? this.stats.users.remote.total
: sum(this.stats.users.remote.inc, negate(this.stats.users.remote.dec))
@ -314,6 +320,7 @@ export default Vue.extend({
bytes: true,
series: [{
name: 'All',
type: 'line',
data: this.format(
sum(
this.stats.drive.local.incSize,
@ -324,15 +331,19 @@ export default Vue.extend({
)
}, {
name: 'Local +',
type: 'area',
data: this.format(this.stats.drive.local.incSize)
}, {
name: 'Local -',
type: 'area',
data: this.format(negate(this.stats.drive.local.decSize))
}, {
name: 'Remote +',
type: 'area',
data: this.format(this.stats.drive.remote.incSize)
}, {
name: 'Remote -',
type: 'area',
data: this.format(negate(this.stats.drive.remote.decSize))
}]
};
@ -343,12 +354,15 @@ export default Vue.extend({
bytes: true,
series: [{
name: 'Combined',
type: 'line',
data: this.format(sum(this.stats.drive.local.totalSize, this.stats.drive.remote.totalSize))
}, {
name: 'Local',
type: 'area',
data: this.format(this.stats.drive.local.totalSize)
}, {
name: 'Remote',
type: 'area',
data: this.format(this.stats.drive.remote.totalSize)
}]
};
@ -358,6 +372,7 @@ export default Vue.extend({
return {
series: [{
name: 'All',
type: 'line',
data: this.format(
sum(
this.stats.drive.local.incCount,
@ -368,15 +383,19 @@ export default Vue.extend({
)
}, {
name: 'Local +',
type: 'area',
data: this.format(this.stats.drive.local.incCount)
}, {
name: 'Local -',
type: 'area',
data: this.format(negate(this.stats.drive.local.decCount))
}, {
name: 'Remote +',
type: 'area',
data: this.format(this.stats.drive.remote.incCount)
}, {
name: 'Remote -',
type: 'area',
data: this.format(negate(this.stats.drive.remote.decCount))
}]
};
@ -386,12 +405,15 @@ export default Vue.extend({
return {
series: [{
name: 'Combined',
type: 'line',
data: this.format(sum(this.stats.drive.local.totalCount, this.stats.drive.remote.totalCount))
}, {
name: 'Local',
type: 'area',
data: this.format(this.stats.drive.local.totalCount)
}, {
name: 'Remote',
type: 'area',
data: this.format(this.stats.drive.remote.totalCount)
}]
};

View File

@ -2,14 +2,14 @@
<div class="zyknedwtlthezamcjlolyusmipqmjgxz">
<div>
<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>
</header>
<div ref="cpu"></div>
</div>
<div>
<header>
<span>%fa:memory% MEM <span>{{ memP }}%</span></span>
<span><fa icon="memory"/> MEM <span>{{ memP }}%</span></span>
<span v-if="meta"></span>
</header>
<div ref="mem"></div>

View File

@ -11,54 +11,54 @@
<div v-if="stats" class="stats">
<div>
<div>
<div>%fa:user%</div>
<div><fa icon="user"/></div>
<div>
<span>%i18n:@accounts%</span>
<b class="primary">{{ stats.originalUsersCount | number }}</b>
</div>
</div>
<div>
<span>%fa:home% %i18n:@this-instance%</span>
<span @click="setChartSrc('users')">%fa:chart-bar R%</span>
<span><fa icon="home"/> %i18n:@this-instance%</span>
<span @click="setChartSrc('users')"><fa :icon="['far', 'chart-bar']"/></span>
</div>
</div>
<div>
<div>
<div>%fa:pencil-alt%</div>
<div><fa icon="pencil-alt"/></div>
<div>
<span>%i18n:@notes%</span>
<b class="primary">{{ stats.originalNotesCount | number }}</b>
</div>
</div>
<div>
<span>%fa:home% %i18n:@this-instance%</span>
<span @click="setChartSrc('notes')">%fa:chart-bar R%</span>
<span><fa icon="home"/> %i18n:@this-instance%</span>
<span @click="setChartSrc('notes')"><fa :icon="['far', 'chart-bar']"/></span>
</div>
</div>
<div>
<div>
<div>%fa:database%</div>
<div><fa icon="database"/></div>
<div>
<span>%i18n:@drive%</span>
<b>{{ stats.driveUsageLocal | bytes }}</b>
</div>
</div>
<div>
<span>%fa:home% %i18n:@this-instance%</span>
<span @click="setChartSrc('drive')">%fa:chart-bar R%</span>
<span><fa icon="home"/> %i18n:@this-instance%</span>
<span @click="setChartSrc('drive')"><fa :icon="['far', 'chart-bar']"/></span>
</div>
</div>
<div>
<div>
<div>%fa:hdd R%</div>
<div><fa :icon="['far', 'hdd']"/></div>
<div>
<span>%i18n:@instances%</span>
<b>{{ stats.instances | number }}</b>
</div>
</div>
<div>
<span>%fa:globe% %i18n:@federated%</span>
<span @click="setChartSrc('federation-instances-total')">%fa:chart-bar R%</span>
<span><fa icon="globe"/> %i18n:@federated%</span>
<span @click="setChartSrc('federation-instances-total')"><fa :icon="['far', 'chart-bar']"/></span>
</div>
</div>
</div>

View File

@ -1,19 +1,20 @@
<template>
<div class="tumhkfkmgtvzljezfvmgkeurkfncshbe">
<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">
<ui-horizon-group inputs>
<ui-input v-model="name">
<span>%i18n:@add-emoji.name%</span>
<span slot="text">%i18n:@add-emoji.name-desc%</span>
<span slot="desc">%i18n:@add-emoji.name-desc%</span>
</ui-input>
<ui-input v-model="aliases">
<span>%i18n:@add-emoji.aliases%</span>
<span slot="text">%i18n:@add-emoji.aliases-desc%</span>
<span slot="desc">%i18n:@add-emoji.aliases-desc%</span>
</ui-input>
</ui-horizon-group>
<ui-input v-model="url">
<i slot="icon"><fa icon="link"/></i>
<span>%i18n:@add-emoji.url%</span>
</ui-input>
<ui-info>%i18n:@add-emoji.info%</ui-info>
@ -22,7 +23,7 @@
</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">
<img :src="emoji.url" :alt="emoji.name" style="width: 64px;"/>
<ui-horizon-group inputs>
@ -34,11 +35,12 @@
</ui-input>
</ui-horizon-group>
<ui-input v-model="emoji.url">
<i slot="icon"><fa icon="link"/></i>
<span>%i18n:@add-emoji.url%</span>
</ui-input>
<ui-horizon-group>
<ui-button @click="updateEmoji(emoji)">%fa:save R% %i18n:@emojis.update%</ui-button>
<ui-button @click="removeEmoji(emoji)">%fa:trash-alt R% %i18n:@emojis.remove%</ui-button>
<ui-button @click="updateEmoji(emoji)"><fa :icon="['far', 'save']"/> %i18n:@emojis.update%</ui-button>
<ui-button @click="removeEmoji(emoji)"><fa :icon="['far', 'trash-alt']"/> %i18n:@emojis.remove%</ui-button>
</ui-horizon-group>
</section>
</ui-card>
@ -67,17 +69,24 @@ export default Vue.extend({
(this as any).api('admin/emoji/add', {
name: this.name,
url: this.url,
aliases: this.aliases.split(' ')
aliases: this.aliases.split(' ').filter(x => x.length > 0)
}).then(() => {
//(this as any).os.apis.dialog({ text: `Added` });
this.$swal({
type: 'success',
text: '%i18n:@add-emoji.added%'
});
this.fetchEmojis();
}).catch(e => {
//(this as any).os.apis.dialog({ text: `Failed ${e}` });
this.$swal({
type: 'error',
text: e
});
});
},
fetchEmojis() {
(this as any).api('admin/emoji/list').then(emojis => {
emojis.reverse();
emojis.forEach(e => e.aliases = (e.aliases || []).join(' '));
this.emojis = emojis;
});
@ -88,22 +97,42 @@ export default Vue.extend({
id: emoji.id,
name: emoji.name,
url: emoji.url,
aliases: emoji.aliases.split(' ')
aliases: emoji.aliases.split(' ').filter(x => x.length > 0)
}).then(() => {
//(this as any).os.apis.dialog({ text: `Updated` });
this.$swal({
type: 'success',
text: '%i18n:@updated%'
});
}).catch(e => {
//(this as any).os.apis.dialog({ text: `Failed ${e}` });
this.$swal({
type: 'error',
text: e
});
});
},
removeEmoji(emoji) {
(this as any).api('admin/emoji/remove', {
id: emoji.id
}).then(() => {
//(this as any).os.apis.dialog({ text: `Removed` });
this.fetchEmojis();
}).catch(e => {
//(this as any).os.apis.dialog({ text: `Failed ${e}` });
this.$swal({
type: 'warning',
text: '%i18n:@remove-emoji.are-you-sure%'.replace('$1', emoji.name),
showCancelButton: true
}).then(res => {
if (!res.value) return;
(this as any).api('admin/emoji/remove', {
id: emoji.id
}).then(() => {
this.$swal({
type: 'success',
text: '%i18n:@remove-emoji.removed%'
});
this.fetchEmojis();
}).catch(e => {
this.$swal({
type: 'error',
text: e
});
});
});
}
}

View File

@ -1,7 +1,7 @@
<template>
<div class="mk-admin" :class="{ isMobile }">
<header v-show="isMobile">
<button class="nav" @click="navOpend = true">%fa:bars%</button>
<button class="nav" @click="navOpend = true"><fa icon="bars"/></button>
<span>MisskeyMyAdmin</span>
</header>
<div class="nav-backdrop"
@ -18,30 +18,30 @@
<p class="name">{{ $store.state.i | userName }}</p>
</div>
<ul>
<li @click="nav('dashboard')" :class="{ active: page == 'dashboard' }">%fa:home .fw%%i18n:@dashboard%</li>
<li @click="nav('instance')" :class="{ active: page == 'instance' }">%fa:cog .fw%%i18n:@instance%</li>
<li @click="nav('users')" :class="{ active: page == 'users' }">%fa:users .fw%%i18n:@users%</li>
<li @click="nav('emoji')" :class="{ active: page == 'emoji' }">%fa:grin R .fw%%i18n:@emoji%</li>
<li @click="nav('announcements')" :class="{ active: page == 'announcements' }">%fa:broadcast-tower .fw%%i18n:@announcements%</li>
<li @click="nav('hashtags')" :class="{ active: page == 'hashtags' }">%fa:hashtag .fw%%i18n:@hashtags%</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 icon="cog" fixed-width/>%i18n:@instance%</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 :icon="['far', 'grin']" fixed-width/>%i18n:@emoji%</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 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> -->
</ul>
<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 class="version">
<small>Misskey {{ version }}</small>
</div>
</nav>
<main>
<div v-show="page == 'dashboard'"><x-dashboard/></div>
<div v-show="page == 'instance'"><x-instance/></div>
<div v-if="page == 'dashboard'"><x-dashboard/></div>
<div v-if="page == 'instance'"><x-instance/></div>
<div v-if="page == 'users'"><x-users/></div>
<div v-show="page == 'emoji'"><x-emoji/></div>
<div v-show="page == 'announcements'"><x-announcements/></div>
<div v-show="page == 'hashtags'"><x-hashtags/></div>
<div v-if="page == 'emoji'"><x-emoji/></div>
<div v-if="page == 'announcements'"><x-announcements/></div>
<div v-if="page == 'hashtags'"><x-hashtags/></div>
<div v-if="page == 'drive'"></div>
<div v-if="page == 'update'"></div>
</main>
@ -126,7 +126,7 @@ export default Vue.extend({
line-height $headerHeight
border-right solid 1px rgba(#000, 0.1)
> [data-fa]
> [data-icon]
transition all 0.2s ease
> nav
@ -188,7 +188,7 @@ export default Vue.extend({
&:hover
color #fff
> [data-fa]
> [data-icon]
margin-right 6px
> .version
@ -218,7 +218,7 @@ export default Vue.extend({
&:hover
color #fff
> [data-fa]
> [data-icon]
margin-right 6px
&.active

View File

@ -1,28 +1,78 @@
<template>
<div class="axbwjelsbymowqjyywpirzhdlszoncqs">
<ui-card>
<div slot="title">%fa:cog% %i18n:@instance%</div>
<section class="fit-top">
<div slot="title"><fa icon="cog"/> %i18n:@instance%</div>
<section class="fit-top fit-bottom">
<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="bannerUrl"><i slot="icon"><fa icon="link"/></i>%i18n:@banner-url%</ui-input>
<ui-input v-model="languages"><i slot="icon"><fa icon="language"/></i>%i18n:@languages%<span slot="desc">%i18n:@languages-desc%</span></ui-input>
</section>
<section class="fit-bottom">
<header><fa icon="headset"/> %i18n:@maintainer-config%</header>
<ui-input v-model="maintainerName">%i18n:@maintainer-name%</ui-input>
<ui-input v-model="maintainerEmail" type="email"><i slot="icon"><fa :icon="['far', 'envelope']"/></i>%i18n:@maintainer-email%</ui-input>
</section>
<section class="fit-top fit-bottom">
<ui-input v-model="maxNoteTextLength">%i18n:@max-note-text-length%</ui-input>
</section>
<section class="fit-bottom">
<header><fa icon="cloud"/> %i18n:@drive-config%</header>
<ui-switch v-model="cacheRemoteFiles">%i18n:@cache-remote-files%<span slot="desc">%i18n:@cache-remote-files-desc%</span></ui-switch>
<ui-input v-model="localDriveCapacityMb">%i18n:@local-drive-capacity-mb%<span slot="suffix">MB</span><span slot="desc">%i18n:@mb%</span></ui-input>
<ui-input v-model="remoteDriveCapacityMb" :disabled="!cacheRemoteFiles">%i18n:@remote-drive-capacity-mb%<span slot="suffix">MB</span><span slot="desc">%i18n:@mb%</span></ui-input>
</section>
<section class="fit-bottom">
<header><fa icon="shield-alt"/> %i18n:@recaptcha-config%</header>
<ui-switch v-model="enableRecaptcha">%i18n:@enable-recaptcha%</ui-switch>
<ui-info>%i18n:@recaptcha-info%</ui-info>
<ui-input v-model="recaptchaSiteKey" :disabled="!enableRecaptcha"><i slot="icon"><fa icon="key"/></i>%i18n:@recaptcha-site-key%</ui-input>
<ui-input v-model="recaptchaSecretKey" :disabled="!enableRecaptcha"><i slot="icon"><fa icon="key"/></i>%i18n:@recaptcha-secret-key%</ui-input>
</section>
<section>
<header><fa icon="ghost"/> %i18n:@proxy-account-config%</header>
<ui-info>%i18n:@proxy-account-info%</ui-info>
<ui-input v-model="proxyAccount"><span slot="prefix">@</span>%i18n:@proxy-account-username%<span slot="desc">%i18n:@proxy-account-username-desc%</span></ui-input>
<ui-info warn>%i18n:@proxy-account-warn%</ui-info>
</section>
<section>
<ui-switch v-model="disableRegistration">%i18n:@disable-registration%</ui-switch>
</section>
<section>
<ui-switch v-model="disableLocalTimeline">%i18n:@disable-local-timeline%</ui-switch>
</section>
<section>
<ui-button @click="updateMeta">%i18n:@save%</ui-button>
</section>
</ui-card>
<ui-card>
<div slot="title">%i18n:@disable-registration%</div>
<div slot="title">%i18n:@invite%</div>
<section>
<input type="checkbox" v-model="disableRegistration" @change="updateMeta">
<button class="ui" @click="invite">%i18n:@invite%</button>
<ui-button @click="invite">%i18n:@invite%</ui-button>
<p v-if="inviteCode">Code: <code>{{ inviteCode }}</code></p>
</section>
</ui-card>
<ui-card>
<div slot="title">%i18n:@disable-local-timeline%</div>
<div slot="title"><fa :icon="['fab', 'twitter']"/> %i18n:@twitter-integration-config%</div>
<section>
<input type="checkbox" v-model="disableLocalTimeline" @change="updateMeta">
<ui-switch v-model="enableTwitterIntegration">%i18n:@enable-twitter-integration%</ui-switch>
<ui-info>%i18n:@twitter-integration-info%</ui-info>
<ui-input v-model="twitterConsumerKey" :disabled="!enableTwitterIntegration"><i slot="icon"><fa icon="key"/></i>%i18n:@twitter-integration-consumer-key%</ui-input>
<ui-input v-model="twitterConsumerSecret" :disabled="!enableTwitterIntegration"><i slot="icon"><fa icon="key"/></i>%i18n:@twitter-integration-consumer-secret%</ui-input>
<ui-button @click="updateMeta">%i18n:@save%</ui-button>
</section>
</ui-card>
<ui-card>
<div slot="title"><fa :icon="['fab', 'github']"/> %i18n:@github-integration-config%</div>
<section>
<ui-switch v-model="enableGithubIntegration">%i18n:@enable-github-integration%</ui-switch>
<ui-info>%i18n:@github-integration-info%</ui-info>
<ui-input v-model="githubClientId" :disabled="!enableGithubIntegration"><i slot="icon"><fa icon="key"/></i>%i18n:@github-integration-client-id%</ui-input>
<ui-input v-model="githubClientSecret" :disabled="!enableGithubIntegration"><i slot="icon"><fa icon="key"/></i>%i18n:@github-integration-client-secret%</ui-input>
<ui-button @click="updateMeta">%i18n:@save%</ui-button>
</section>
</ui-card>
</div>
@ -34,20 +84,54 @@ import Vue from "vue";
export default Vue.extend({
data() {
return {
maintainerName: null,
maintainerEmail: null,
disableRegistration: false,
disableLocalTimeline: false,
bannerUrl: null,
name: null,
description: null,
languages: null,
cacheRemoteFiles: false,
localDriveCapacityMb: null,
remoteDriveCapacityMb: null,
maxNoteTextLength: null,
enableRecaptcha: false,
recaptchaSiteKey: null,
recaptchaSecretKey: null,
enableTwitterIntegration: false,
twitterConsumerKey: null,
twitterConsumerSecret: null,
enableGithubIntegration: false,
githubClientId: null,
githubClientSecret: null,
proxyAccount: null,
inviteCode: null,
};
},
created() {
(this as any).os.getMeta().then(meta => {
this.maintainerName = meta.maintainer.name;
this.maintainerEmail = meta.maintainer.email;
this.bannerUrl = meta.bannerUrl;
this.name = meta.name;
this.description = meta.description;
this.languages = meta.langs.join(' ');
this.cacheRemoteFiles = meta.cacheRemoteFiles;
this.localDriveCapacityMb = meta.driveCapacityPerLocalUserMb;
this.remoteDriveCapacityMb = meta.driveCapacityPerRemoteUserMb;
this.maxNoteTextLength = meta.maxNoteTextLength;
this.enableRecaptcha = meta.enableRecaptcha;
this.recaptchaSiteKey = meta.recaptchaSiteKey;
this.recaptchaSecretKey = meta.recaptchaSecretKey;
this.proxyAccount = meta.proxyAccount;
this.enableTwitterIntegration = meta.enableTwitterIntegration;
this.twitterConsumerKey = meta.twitterConsumerKey;
this.twitterConsumerSecret = meta.twitterConsumerSecret;
this.enableGithubIntegration = meta.enableGithubIntegration;
this.githubClientId = meta.githubClientId;
this.githubClientSecret = meta.githubClientSecret;
});
},
@ -56,21 +140,47 @@ export default Vue.extend({
(this as any).api('admin/invite').then(x => {
this.inviteCode = x.code;
}).catch(e => {
//(this as any).os.apis.dialog({ text: `Failed ${e}` });
this.$swal({
type: 'error',
text: e
});
});
},
updateMeta() {
(this as any).api('admin/update-meta', {
maintainerName: this.maintainerName,
maintainerEmail: this.maintainerEmail,
disableRegistration: this.disableRegistration,
disableLocalTimeline: this.disableLocalTimeline,
bannerUrl: this.bannerUrl,
name: this.name,
description: this.description
description: this.description,
langs: this.languages.split(' '),
cacheRemoteFiles: this.cacheRemoteFiles,
localDriveCapacityMb: parseInt(this.localDriveCapacityMb, 10),
remoteDriveCapacityMb: parseInt(this.remoteDriveCapacityMb, 10),
maxNoteTextLength: parseInt(this.maxNoteTextLength, 10),
enableRecaptcha: this.enableRecaptcha,
recaptchaSiteKey: this.recaptchaSiteKey,
recaptchaSecretKey: this.recaptchaSecretKey,
proxyAccount: this.proxyAccount,
enableTwitterIntegration: this.enableTwitterIntegration,
twitterConsumerKey: this.twitterConsumerKey,
twitterConsumerSecret: this.twitterConsumerSecret,
enableGithubIntegration: this.enableGithubIntegration,
githubClientId: this.githubClientId,
githubClientSecret: this.githubClientSecret,
}).then(() => {
//(this as any).os.apis.dialog({ text: `Saved` });
this.$swal({
type: 'success',
text: '%i18n:@saved%'
});
}).catch(e => {
//(this as any).os.apis.dialog({ text: `Failed ${e}` });
this.$swal({
type: 'error',
text: e
});
});
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
<template>
<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>
<p class="text">
<span>{{ '%i18n:@description%'.substr(0, '%i18n:@description%'.indexOf('{')) }}</span>

View File

@ -1,6 +1,6 @@
<template>
<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">
<div class="meter"><div :style="meterStyle"></div></div>

View File

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

View File

@ -1,6 +1,6 @@
<template>
<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>
</div>
</template>

View File

@ -1,6 +1,6 @@
<template>
<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>
</template>

View File

@ -1,6 +1,6 @@
<template>
<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>
<div style="overflow: hidden; line-height: 28px;">
@ -51,13 +51,13 @@
<div class="player" v-if="game.isEnded">
<div>
<button @click="logPos = 0" :disabled="logPos == 0">%fa:angle-double-left%</button>
<button @click="logPos--" :disabled="logPos == 0">%fa:angle-left%</button>
<button @click="logPos = 0" :disabled="logPos == 0"><fa icon="angle-double-left"/></button>
<button @click="logPos--" :disabled="logPos == 0"><fa icon="angle-left"/></button>
</div>
<span>{{ logPos }} / {{ logs.length }}</span>
<div>
<button @click="logPos++" :disabled="logPos == logs.length">%fa:angle-right%</button>
<button @click="logPos = logs.length" :disabled="logPos == logs.length">%fa:angle-double-right%</button>
<button @click="logPos++" :disabled="logPos == logs.length"><fa icon="angle-right"/></button>
<button @click="logPos = logs.length" :disabled="logPos == logs.length"><fa icon="angle-double-right"/></button>
</div>
</div>

View File

@ -17,13 +17,13 @@
</header>
<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 v-for="(x, i) in game.settings.map.join('')"
:data-none="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 == 'w'"><template v-if="$store.state.device.darkmode">%fa:circle%</template><template v-else>%fa:circle R%</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 :icon="['far', 'circle']"/></template><template v-else><fa icon="circle"/></template></template>
</div>
</div>
</div>

View File

@ -1,7 +1,7 @@
<template>
<div class="mk-google">
<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>
</template>

View File

@ -39,7 +39,7 @@ import urlPreview from './url-preview.vue';
import twitterSetting from './twitter-setting.vue';
import githubSetting from './github-setting.vue';
import fileTypeIcon from './file-type-icon.vue';
import Reversi from './games/reversi/reversi.vue';
import emoji from './emoji.vue';
import welcomeTimeline from './welcome-timeline.vue';
import uiInput from './ui/input.vue';
import uiButton from './ui/button.vue';
@ -93,7 +93,7 @@ Vue.component('mk-url-preview', urlPreview);
Vue.component('mk-twitter-setting', twitterSetting);
Vue.component('mk-github-setting', githubSetting);
Vue.component('mk-file-type-icon', fileTypeIcon);
Vue.component('mk-reversi', Reversi);
Vue.component('mk-emoji', emoji);
Vue.component('mk-welcome-timeline', welcomeTimeline);
Vue.component('ui-input', uiInput);
Vue.component('ui-button', uiButton);

View File

@ -1,7 +1,7 @@
<template>
<div class="mk-media-banner">
<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>
<span>%i18n:@click-to-show%</span>
</div>
@ -18,7 +18,7 @@
:title="media.name"
:download="media.name"
>
<span class="icon">%fa:download%</span>
<span class="icon"><fa icon="download"/></span>
<b>{{ media.name }}</b>
</a>
</div>

View File

@ -4,7 +4,9 @@
<div class="popover" :class="{ hukidasi }" ref="popover">
<template v-for="item, i in items">
<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>
</div>
</div>
@ -188,6 +190,9 @@ export default Vue.extend({
color var(--primaryForeground)
background var(--primaryDarken10)
> [data-icon]
margin-right 4px
> div
margin 8px 0
height 1px

View File

@ -14,13 +14,13 @@
<div class="file" @click="file = null" v-if="file">{{ file.name }}</div>
<mk-uploader ref="uploader" @uploaded="onUploaded"/>
<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 class="attach-from-local" @click="chooseFile" title="%i18n:@attach-from-local%">
%fa:upload%
<fa icon="upload"/>
</button>
<button class="attach-from-drive" @click="chooseFileFromDrive" title="%i18n:@attach-from-drive%">
%fa:R folder-open%
<fa :icon="['far', 'folder-open']"/>
</button>
<input ref="file" type="file" @change="onChangeFile"/>
</div>

View File

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

View File

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

View File

@ -2,7 +2,7 @@
<div class="mk-messaging" :data-compact="compact">
<div class="search" v-if="!compact" :style="{ top: headerTop + 'px' }">
<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%"/>
</div>
<div class="result">
@ -45,7 +45,7 @@
</template>
</div>
<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>
</template>
@ -213,7 +213,7 @@ export default Vue.extend({
width 38px
pointer-events none
> [data-fa]
> i
display block
position absolute
top 0
@ -418,7 +418,7 @@ export default Vue.extend({
text-align center
color #aaa
> [data-fa]
> [data-icon]
margin-right 4px
// TODO: element base media query

View File

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

View File

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

View File

@ -7,8 +7,6 @@
<a :href="feedbackUrl" target="_blank">%i18n:@feedback%</a>
<i></i>
<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>
</template>

View File

@ -6,18 +6,18 @@
<span class="is-bot" v-if="note.user.isBot">bot</span>
<span class="is-cat" v-if="note.user.isCat">cat</span>
<span class="username"><mk-acct :user="note.user"/></span>
<span class="is-verified" v-if="note.user.isVerified" title="%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">
<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">
<mk-time :time="note.createdAt"/>
</router-link>
<span class="visibility" v-if="note.visibility != 'public'">
<template v-if="note.visibility == 'home'">%fa:home%</template>
<template v-if="note.visibility == 'followers'">%fa:unlock%</template>
<template v-if="note.visibility == 'specified'">%fa:envelope%</template>
<template v-if="note.visibility == 'private'">%fa:lock%</template>
<template v-if="note.visibility == 'home'"><fa icon="home"/></template>
<template v-if="note.visibility == 'followers'"><fa icon="unlock"/></template>
<template v-if="note.visibility == 'specified'"><fa icon="envelope"/></template>
<template v-if="note.visibility == 'private'"><fa icon="lock"/></template>
</span>
</div>
</header>

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@
</ui-input>
<ui-input v-model="password" type="password" required styl="fill">
<span>%i18n:@password%</span>
<span slot="prefix">%fa:lock%</span>
<span slot="prefix"><fa icon="lock"/></span>
</ui-input>
<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>

View File

@ -3,39 +3,39 @@
<template v-if="meta">
<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 slot="prefix">%fa:id-card-alt%</span>
<p slot="text" v-html="'%i18n:@invitation-info%'.replace('{}', meta.maintainer.url)"></p>
<span slot="prefix"><fa icon="id-card-alt"/></span>
<p slot="desc" v-html="'%i18n:@invitation-info%'.replace('{}', 'mailto:' + meta.maintainer.email)"></p>
</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">
<span>%i18n:@username%</span>
<span slot="prefix">@</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 == 'ok'" style="color:#3CB7B5">%fa:check .fw% %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 == 'error'" style="color:#FF1161">%fa:exclamation-triangle .fw% %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 == 'min-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-short%</p>
<p slot="text" v-if="usernameState == 'max-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-long%</p>
<p slot="desc" v-if="usernameState == 'wait'" style="color:#999"><fa icon="spinner .pulse" fixed-width/> %i18n:@checking%</p>
<p slot="desc" v-if="usernameState == 'ok'" style="color:#3CB7B5"><fa icon="check" fixed-width/> %i18n:@available%</p>
<p slot="desc" v-if="usernameState == 'unavailable'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@unavailable%</p>
<p slot="desc" v-if="usernameState == 'error'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@error%</p>
<p slot="desc" v-if="usernameState == 'invalid-format'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@invalid-format%</p>
<p slot="desc" v-if="usernameState == 'min-range'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@too-short%</p>
<p slot="desc" v-if="usernameState == 'max-range'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@too-long%</p>
</ui-input>
<ui-input v-model="password" type="password" :autocomplete="Math.random()" required @input="onChangePassword" :with-password-meter="true" styl="fill">
<span>%i18n:@password%</span>
<span slot="prefix">%fa:lock%</span>
<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 == 'medium'" style="color:#3CB7B5">%fa:check .fw% %i18n:@normal-password%</p>
<p slot="text" v-if="passwordStrength == 'high'" style="color:#3CB7B5">%fa:check .fw% %i18n:@strong-password%</p>
<span slot="prefix"><fa icon="lock"/></span>
<div slot="desc">
<p v-if="passwordStrength == 'low'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@weak-password%</p>
<p v-if="passwordStrength == 'medium'" style="color:#3CB7B5"><fa icon="check" fixed-width/> %i18n:@normal-password%</p>
<p v-if="passwordStrength == 'high'" style="color:#3CB7B5"><fa icon="check" fixed-width/> %i18n:@strong-password%</p>
</div>
</ui-input>
<ui-input v-model="retypedPassword" type="password" :autocomplete="Math.random()" required @input="onChangePasswordRetype" styl="fill">
<span>%i18n:@password% (%i18n:@retype%)</span>
<span slot="prefix">%fa:lock%</span>
<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 == 'not-match'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@password-not-matched%</p>
<span slot="prefix"><fa icon="lock"/></span>
<div slot="desc">
<p v-if="passwordRetypeState == 'match'" style="color:#3CB7B5"><fa icon="check" fixed-width/> %i18n:@password-matched%</p>
<p v-if="passwordRetypeState == 'not-match'" style="color:#FF1161"><fa icon="exclamation-triangle" fixed-width/> %i18n:@password-not-matched%</p>
</div>
</ui-input>
<div v-if="meta.recaptchaSitekey != null" class="g-recaptcha" :data-sitekey="meta.recaptchaSitekey" style="margin: 16px 0;"></div>
<div v-if="meta.enableRecaptcha" class="g-recaptcha" :data-sitekey="meta.recaptchaSiteKey" style="margin: 16px 0;"></div>
<ui-button type="submit">%i18n:@create%</ui-button>
</template>
</form>
@ -130,7 +130,7 @@ export default Vue.extend({
username: this.username,
password: this.password,
invitationCode: this.invitationCode,
'g-recaptcha-response': this.meta.recaptchaSitekey != null ? (window as any).grecaptcha.getResponse() : null
'g-recaptcha-response': this.meta.enableRecaptcha ? (window as any).grecaptcha.getResponse() : null
}, true).then(() => {
(this as any).api('signin', {
username: this.username,
@ -141,7 +141,7 @@ export default Vue.extend({
}).catch(() => {
alert('%i18n:@some-error%');
if (this.meta.recaptchaSitekey != null) {
if (this.meta.enableRecaptcha) {
(window as any).grecaptcha.reset();
}
});

View File

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

View File

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

View File

@ -25,7 +25,7 @@
</label>
<details class="creator">
<summary>%fa:palette% %i18n:@create-a-theme%</summary>
<summary><fa icon="palette"/> %i18n:@create-a-theme%</summary>
<div>
<span>%i18n:@base-theme%:</span>
<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>
<color-picker v-model="myThemeText"/>
</div>
<ui-button @click="preview()">%fa:eye% %i18n:@preview-created-theme%</ui-button>
<ui-button primary @click="gen()">%fa:save R% %i18n:@save-created-theme%</ui-button>
<ui-button @click="preview()"><fa icon="eye"/> %i18n:@preview-created-theme%</ui-button>
<ui-button primary @click="gen()"><fa :icon="['far', 'save']"/> %i18n:@save-created-theme%</ui-button>
</details>
<details>
<summary>%fa:download% %i18n:@install-a-theme%</summary>
<ui-button @click="import_()">%fa:file-import% %i18n:@import%</ui-button>
<summary><fa icon="download"/> %i18n:@install-a-theme%</summary>
<ui-button @click="import_()"><fa icon="file-import"/> %i18n:@import%</ui-button>
<input ref="file" type="file" accept=".misskeytheme" style="display:none;" @change="onUpdateImportFile"/>
<p>%i18n:@import-by-code%:</p>
<ui-textarea v-model="installThemeCode">
<span>%i18n:@theme-code%</span>
</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>
<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%">
<optgroup label="%i18n:@builtin-themes%">
<option v-for="x in builtinThemes" :value="x.id" :key="x.id">{{ x.name }}</option>
@ -89,8 +89,8 @@
<ui-textarea readonly :value="selectedThemeCode">
<span>%i18n:@theme-code%</span>
</ui-textarea>
<ui-button @click="export_()" link :download="`${selectedTheme.name}.misskeytheme`" ref="export">%fa: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="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 :icon="['far', 'trash-alt']"/> %i18n:@uninstall%</ui-button>
</template>
</details>
</div>

View File

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

View File

@ -12,7 +12,11 @@
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
inject: ['horizonGrouped'],
inject: {
horizonGrouped: {
default: false
}
},
props: {
type: {
type: String,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,7 +3,7 @@
<ol v-if="uploads.length > 0">
<li v-for="ctx in uploads" :key="ctx.id">
<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">
<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>
@ -155,7 +155,7 @@ export default Vue.extend({
text-overflow ellipsis
overflow hidden
> [data-fa]
> [data-icon]
margin-right 4px
> .status

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
<template>
<div class="mkw-hashtags">
<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'">
<mk-trends/>

View File

@ -1,7 +1,7 @@
<template>
<div class="mkw-memo">
<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">
<textarea v-model="text" placeholder="%i18n:@memo%" @input="onChange"></textarea>

View File

@ -1,9 +1,9 @@
<template>
<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">
<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 v-for="image in images" :class="$style.img" :style="`background-image: url(${image.thumbnailUrl || image.url})`"></div>
</div>
@ -94,7 +94,7 @@ export default define({
text-align center
color #aaa
> [data-fa]
> [data-icon]
margin-right 4px
</style>

View File

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

View File

@ -1,11 +1,11 @@
<template>
<div class="mkw-rss">
<mk-widget-container :show-header="!props.compact">
<template slot="header">%fa:rss-square%RSS</template>
<button slot="func" title="設定" @click="setting">%fa:cog%</button>
<template slot="header"><fa icon="rss-square"/>RSS</template>
<button slot="func" title="設定" @click="setting"><fa icon="cog"/></button>
<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>
<a v-for="item in items" :href="item.link" target="_blank">{{ item.title }}</a>
</div>
@ -85,7 +85,7 @@ export default define({
text-align center
color #aaa
> [data-fa]
> [data-icon]
margin-right 4px
&[data-mobile]

View File

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

View File

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

View File

@ -1,6 +1,6 @@
<template>
<div class="info">
<p>Maintainer: <b><a :href="meta.maintainer.url" target="_blank">{{ meta.maintainer.name }}</a></b></p>
<p>Maintainer: <b><a :href="'mailto:' + meta.maintainer.email" target="_blank">{{ meta.maintainer.name }}</a></b></p>
<p>Machine: {{ meta.machine }}</p>
<p>Node: {{ meta.node }}</p>
</div>

View File

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

View File

@ -1,10 +1,10 @@
<template>
<div class="mkw-server">
<mk-widget-container :show-header="props.design == 0" :naked="props.design == 2">
<template slot="header">%fa:server%%i18n:@title%</template>
<button slot="func" @click="toggle" title="%i18n:@toggle%">%fa:sort%</button>
<template slot="header"><fa icon="server"/>%i18n:@title%</template>
<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">
<x-cpu-memory v-show="props.view == 0" :connection="connection"/>
<x-cpu v-show="props.view == 1" :connection="connection" :meta="meta"/>
@ -87,7 +87,7 @@ export default define({
text-align center
color #aaa
> [data-fa]
> [data-icon]
margin-right 4px
</style>

View File

@ -1,6 +1,6 @@
<template>
<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>
</template>
@ -88,7 +88,7 @@ export default define({
font-size 0.7em
color #999
> [data-fa]
> [data-icon]
margin-right 4px
kbd

View File

@ -1,10 +1,10 @@
<template>
<div class="mk-activity">
<mk-widget-container :show-header="design == 0" :naked="design == 2">
<template slot="header">%fa:chart-bar%%i18n:@title%</template>
<button slot="func" title="%i18n:@toggle%" @click="toggle">%fa:sort%</button>
<template slot="header"><fa icon="chart-bar"/>%i18n:@title%</template>
<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>
<x-calendar v-show="view == 0" :data="[].concat(activity)"/>
<x-chart v-show="view == 1" :data="[].concat(activity)"/>
@ -78,7 +78,7 @@ export default Vue.extend({
text-align center
color #aaa
> [data-fa]
> [data-icon]
margin-right 4px
</style>

View File

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

View File

@ -13,7 +13,7 @@
@change-selection="onChangeSelection"
/>
<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.ok" :disabled="multiple && files.length == 0" @click="ok">%i18n:@ok%</button>
</div>
@ -28,7 +28,7 @@ export default Vue.extend({
default: false
},
title: {
default: '%fa:R file%%i18n:@choose-prompt%'
default: '<fa :icon="['far', 'file']"/>%i18n:@choose-prompt%'
}
},
data() {
@ -62,7 +62,7 @@ export default Vue.extend({
.title
> [data-fa]
> [data-icon]
margin-right 4px
.count

View File

@ -21,7 +21,7 @@ import Vue from 'vue';
export default Vue.extend({
props: {
title: {
default: '%fa:R folder%%i18n:@choose-prompt%'
default: '<fa :icon="['far', 'folder']"/>%i18n:@choose-prompt%'
}
},
methods: {
@ -40,7 +40,7 @@ export default Vue.extend({
.title
> [data-fa]
> [data-icon]
margin-right 4px
.browser

View File

@ -3,13 +3,13 @@
<li v-for="(item, i) in menu" :class="item ? item.type : item === null ? 'divider' : null">
<template v-if="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 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 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"/>
</template>
</template>
@ -113,9 +113,9 @@ export default Vue.extend({
<style lang="stylus" module>
.icon
> *
width 28px
margin-left -28px
text-align center
display inline-block
width 28px
margin-left -28px
text-align center
</style>

View File

@ -1,6 +1,6 @@
<template>
<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">
<vue-cropper ref="cropper"
:src="image.url"
@ -64,7 +64,7 @@ export default Vue.extend({
.header
> [data-fa]
> [data-icon]
margin-right 4px
.img

View File

@ -91,8 +91,6 @@ export default Vue.extend({
</script>
<style lang="stylus" scoped>
.mk-dialog
> .bg
display block

View File

@ -2,7 +2,7 @@
<mk-window ref="window" @closed="destroyDom" width="800px" height="500px" :popout-url="popout">
<template slot="header">
<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>
<mk-drive :class="$style.browser" multiple :init-folder="folder" ref="browser"/>
</mk-window>
@ -39,7 +39,7 @@ export default Vue.extend({
<style lang="stylus" module>
.title
> [data-fa]
> [data-icon]
margin-right 4px
.info

View File

@ -71,27 +71,27 @@ export default Vue.extend({
contextmenu((this as any).os)(e, [{
type: 'item',
text: '%i18n:@contextmenu.rename%',
icon: '%fa:i-cursor%',
icon: 'i-cursor',
action: this.rename
}, {
type: 'item',
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
}, null, {
type: 'item',
text: '%i18n:@contextmenu.copy-url%',
icon: '%fa:link%',
icon: 'link',
action: this.copyUrl
}, {
type: 'link',
href: `${this.file.url}?download`,
text: '%i18n:@contextmenu.download%',
icon: '%fa:download%',
icon: 'download',
}, null, {
type: 'item',
text: '%i18n:common.delete%',
icon: '%fa:R trash-alt%',
icon: ['far', 'trash-alt'],
action: this.deleteFile
}, null, {
type: 'nest',
@ -170,7 +170,7 @@ export default Vue.extend({
copyUrl() {
copyToClipboard(this.file.url);
(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%',
actions: [{
text: '%i18n:common.ok%'

View File

@ -16,8 +16,8 @@
:title="title"
>
<p class="name">
<template v-if="hover">%fa:R folder-open .fw%</template>
<template v-if="!hover">%fa:R folder .fw%</template>
<template v-if="hover"><fa :icon="['far', 'folder-open']" fixed-width/></template>
<template v-if="!hover"><fa :icon="['far', 'folder']" fixed-width/></template>
{{ folder.name }}
</p>
</div>
@ -55,22 +55,22 @@ export default Vue.extend({
contextmenu((this as any).os)(e, [{
type: 'item',
text: '%i18n:@contextmenu.move-to-this-folder%',
icon: '%fa:arrow-right%',
icon: 'arrow-right',
action: this.go
}, {
type: 'item',
text: '%i18n:@contextmenu.show-in-new-window%',
icon: '%fa:R window-restore%',
icon: ['far', 'window-restore'],
action: this.newWindow
}, null, {
type: 'item',
text: '%i18n:@contextmenu.rename%',
icon: '%fa:i-cursor%',
icon: 'i-cursor',
action: this.rename
}, null, {
type: 'item',
text: '%i18n:common.delete%',
icon: '%fa:R trash-alt%',
icon: ['far', 'trash-alt'],
action: this.deleteFolder
}], {
closed: () => {
@ -155,7 +155,7 @@ export default Vue.extend({
switch (err) {
case 'detected-circular-definition':
(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%',
actions: [{
text: '%i18n:common.ok%'
@ -255,7 +255,7 @@ export default Vue.extend({
font-size 0.9em
color var(--desktopDriveFolderFg)
> [data-fa]
> [data-icon]
margin-right 4px
margin-left 2px
text-align left

View File

@ -7,7 +7,7 @@
@dragleave="onDragleave"
@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>
</div>
</template>
@ -110,7 +110,7 @@ export default Vue.extend({
&[data-draghover]
background #eee
[data-fa].cloud
i.cloud
margin-right 4px
</style>

View File

@ -4,10 +4,10 @@
<div class="path" @contextmenu.prevent.stop="() => {}">
<x-nav-folder :class="{ current: folder == null }"/>
<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"/>
</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>
</div>
<!--
@ -138,17 +138,17 @@ export default Vue.extend({
contextmenu((this as any).os)(e, [{
type: 'item',
text: '%i18n:@contextmenu.create-folder%',
icon: '%fa:R folder%',
icon: ['far', 'folder'],
action: this.createFolder
}, {
type: 'item',
text: '%i18n:@contextmenu.upload%',
icon: '%fa:upload%',
icon: 'upload',
action: this.selectLocalFile
}, {
type: 'item',
text: '%i18n:@contextmenu.url-upload%',
icon: '%fa:cloud-upload-alt%',
icon: 'cloud-upload-alt',
action: this.urlUpload
}]);
},
@ -313,7 +313,7 @@ export default Vue.extend({
switch (err) {
case 'detected-circular-definition':
(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%',
actions: [{
text: '%i18n:common.ok%'
@ -343,7 +343,7 @@ export default Vue.extend({
});
(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%',
actions: [{
text: '%i18n:common.ok%'
@ -359,7 +359,7 @@ export default Vue.extend({
}).then(name => {
(this as any).api('drive/folders/create', {
name: name,
folderId: this.folder ? this.folder.id : undefined
parentId: this.folder ? this.folder.id : undefined
}).then(folder => {
this.addFolder(folder, true);
});
@ -613,9 +613,6 @@ export default Vue.extend({
line-height 38px
cursor pointer
i
margin-right 4px
*
pointer-events none
@ -635,7 +632,7 @@ export default Vue.extend({
opacity 0.5
cursor default
> [data-fa]
> [data-icon]
margin 0
> .search

View File

@ -5,13 +5,13 @@
:disabled="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-else-if="u.hasPendingFollowRequestFromYou && !u.isLocked">%fa: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 && u.isLocked">%fa: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-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 icon="hourglass-start"/><template v-if="size == 'big'"> %i18n:@follow-processing%</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 icon="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%</template></template>
</template>
<template v-else>%fa:spinner .pulse .fw%</template>
<template v-else><fa icon="spinner .pulse" fixed-width/></template>
</button>
</template>

View File

@ -11,9 +11,9 @@
</div>
</div>
<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>
<button class="close" @click="destroyDom()" title="%i18n:@close%">%fa:times%</button>
<button class="close" @click="destroyDom()" title="%i18n:@close%"><fa icon="times"/></button>
</div>
</template>
@ -124,7 +124,7 @@ export default Vue.extend({
text-align center
color #aaa
> [data-fa]
> [data-icon]
margin-right 4px
> .refresh
@ -155,7 +155,7 @@ export default Vue.extend({
&:active
color #222
> [data-fa]
> [data-icon]
padding 14px
</style>

View File

@ -1,7 +1,7 @@
<template>
<mk-window ref="window" width="500px" height="560px" :popout-url="popout" @closed="destroyDom">
<span slot="header" :class="$style.header">%fa:gamepad%%i18n:@game%</span>
<mk-reversi :class="$style.content" @gamed="g => game = g"/>
<span slot="header" :class="$style.header"><fa icon="gamepad"/>%i18n:@game%</span>
<x-reversi :class="$style.content" @gamed="g => game = g"/>
</mk-window>
</template>
@ -10,6 +10,9 @@ import Vue from 'vue';
import { url } from '../../../config';
export default Vue.extend({
components: {
XReversi: () => import('../../../common/views/components/games/reversi/reversi.vue')
},
data() {
return {
game: null
@ -27,7 +30,7 @@ export default Vue.extend({
<style lang="stylus" module>
.header
> [data-fa]
> [data-icon]
margin-right 4px
.content

View File

@ -1,7 +1,7 @@
<template>
<div class="mk-home" :data-customize="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 class="adder">
<p>%i18n:@add-widget%</p>
@ -185,7 +185,7 @@ export default Vue.extend({
methods: {
hint() {
(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>' +
'<p>%i18n:common.customization-tips.paragraph2%</p>' +
'<p>%i18n:common.customization-tips.paragraph3%</p>' +
@ -299,7 +299,7 @@ export default Vue.extend({
background var(--primaryDarken10)
transition background 0s ease
> [data-fa]
> [data-icon]
margin-right 8px
> div

View File

@ -1,7 +1,7 @@
<template>
<mk-window ref="window" is-modal width="500px" @before-close="beforeClose" @closed="destroyDom">
<span slot="header" :class="$style.header">
%fa:i-cursor%{{ title }}
<fa icon="i-cursor"/>{{ title }}
</span>
<div :class="$style.body">
@ -76,10 +76,8 @@ export default Vue.extend({
<style lang="stylus" module>
.header
> [data-fa]
> [data-icon]
margin-right 4px
.body

View File

@ -1,7 +1,7 @@
<template>
<div class="ldwbgwstjsdgcjruamauqdrffetqudry" v-if="image.isSensitive && hide && !$store.state.device.alwaysShowNsfw" @click="hide = false">
<div>
<b>%fa:exclamation-triangle% %i18n:@sensitive%</b>
<b><fa icon="exclamation-triangle"/> %i18n:@sensitive%</b>
<span>%i18n:@click-to-show%</span>
</div>
</div>

View File

@ -1,7 +1,7 @@
<template>
<div class="uofhebxjdgksfmltszlxurtjnjjsvioh" v-if="video.isSensitive && hide" @click="hide = false">
<div>
<b>%fa:exclamation-triangle% %i18n:@sensitive%</b>
<b><fa icon="exclamation-triangle"/> %i18n:@sensitive%</b>
<span>%i18n:@click-to-show%</span>
</div>
</div>
@ -12,7 +12,7 @@
@click.prevent="onClick"
:title="video.name"
>
%fa:R play-circle%
<fa :icon="['far', 'play-circle']"/>
</a>
</div>
</template>

View File

@ -1,6 +1,6 @@
<template>
<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-window>
</template>
@ -22,7 +22,7 @@ export default Vue.extend({
<style lang="stylus" module>
.header
> [data-fa]
> [data-icon]
margin-right 4px
.content

View File

@ -1,6 +1,6 @@
<template>
<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-window>
</template>
@ -22,7 +22,7 @@ export default Vue.extend({
<style lang="stylus" module>
.header
> [data-fa]
> [data-icon]
margin-right 4px
.content

View File

@ -7,8 +7,8 @@
@click="fetchConversation"
:disabled="conversationFetching"
>
<template v-if="!conversationFetching">%fa:ellipsis-v%</template>
<template v-if="conversationFetching">%fa:spinner .pulse%</template>
<template v-if="!conversationFetching"><fa icon="ellipsis-v"/></template>
<template v-if="conversationFetching"><fa icon="spinner .pulse"/></template>
</button>
<div class="conversation">
<x-sub v-for="note in conversation" :key="note.id" :note="note"/>
@ -19,7 +19,7 @@
<div class="renote" v-if="isRenote">
<p>
<mk-avatar class="avatar" :user="note.user"/>
%fa:retweet%
<fa icon="retweet"/>
<router-link class="name" :href="note.user | userPage">{{ note.user | userName }}</router-link>
<span>{{ '%i18n:@reposted-by%'.substr(0, '%i18n:@reposted-by%'.indexOf('{')) }}</span>
<a class="name" :href="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</a>
@ -52,7 +52,7 @@
</div>
<mk-poll v-if="p.poll" :note="p"/>
<mk-url-preview v-for="url in urls" :url="url" :key="url" :detail="true"/>
<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a>
<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank"><fa icon="map-marker-alt"/> %i18n:@location%</a>
<div class="map" v-if="p.geo" ref="map"></div>
<div class="renote" v-if="p.renote">
<mk-note-preview :note="p.renote"/>
@ -62,18 +62,18 @@
<footer>
<mk-reactions-viewer :note="p"/>
<button class="replyButton" @click="reply" title="">
<template v-if="p.reply">%fa:reply-all%</template>
<template v-else>%fa:reply%</template>
<template v-if="p.reply"><fa icon="reply-all"/></template>
<template v-else><fa icon="reply"/></template>
<p class="count" v-if="p.repliesCount > 0">{{ p.repliesCount }}</p>
</button>
<button class="renoteButton" @click="renote" title="%i18n:@renote%">
%fa:retweet%<p class="count" v-if="p.renoteCount > 0">{{ p.renoteCount }}</p>
<fa icon="retweet"/><p class="count" v-if="p.renoteCount > 0">{{ p.renoteCount }}</p>
</button>
<button class="reactionButton" :class="{ reacted: p.myReaction != null }" @click="react" ref="reactButton" title="%i18n:@add-reaction%">
%fa:plus%<p class="count" v-if="p.reactions_count > 0">{{ p.reactions_count }}</p>
<fa icon="plus"/><p class="count" v-if="p.reactions_count > 0">{{ p.reactions_count }}</p>
</button>
<button @click="menu" ref="menuButton">
%fa:ellipsis-h%
<fa icon="ellipsis-h"/>
</button>
</footer>
</article>
@ -278,7 +278,7 @@ export default Vue.extend({
margin 0 8px 0 0
border-radius 6px
[data-fa]
[data-icon]
margin-right 4px
.name

View File

@ -15,7 +15,7 @@
</div>
<div class="renote" v-if="isRenote">
<mk-avatar class="avatar" :user="note.user"/>
%fa:retweet%
<fa icon="retweet"/>
<span>{{ '%i18n:@reposted-by%'.substr(0, '%i18n:@reposted-by%'.indexOf('{')) }}</span>
<router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link>
<span>{{ '%i18n:@reposted-by%'.substr('%i18n:@reposted-by%'.indexOf('}') + 1) }}</span>
@ -33,7 +33,7 @@
<div class="content" v-show="appearNote.cw == null || showContent">
<div class="text">
<span v-if="appearNote.isHidden" style="opacity: 0.5">%i18n:@private%</span>
<a class="reply" v-if="appearNote.reply">%fa:reply%</a>
<a class="reply" v-if="appearNote.reply"><fa icon="reply"/></a>
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i" :class="$style.text" :customEmojis="appearNote.emojis"/>
<a class="rp" v-if="appearNote.renote">RN:</a>
</div>
@ -41,7 +41,7 @@
<mk-media-list :media-list="appearNote.files"/>
</div>
<mk-poll v-if="appearNote.poll" :note="appearNote" ref="pollViewer"/>
<a class="location" v-if="appearNote.geo" :href="`https://maps.google.com/maps?q=${appearNote.geo.coordinates[1]},${appearNote.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% 位置情報</a>
<a class="location" v-if="appearNote.geo" :href="`https://maps.google.com/maps?q=${appearNote.geo.coordinates[1]},${appearNote.geo.coordinates[0]}`" target="_blank"><fa icon="map-marker-alt"/> 位置情報</a>
<div class="renote" v-if="appearNote.renote"><mk-note-preview :note="appearNote.renote" :mini="mini"/></div>
<mk-url-preview v-for="url in urls" :url="url" :key="url" :mini="mini"/>
</div>
@ -49,18 +49,18 @@
<footer>
<mk-reactions-viewer :note="appearNote" ref="reactionsViewer"/>
<button class="replyButton" @click="reply()" title="%i18n:@reply%">
<template v-if="appearNote.reply">%fa:reply-all%</template>
<template v-else>%fa:reply%</template>
<template v-if="appearNote.reply"><fa icon="reply-all"/></template>
<template v-else><fa icon="reply"/></template>
<p class="count" v-if="appearNote.repliesCount > 0">{{ appearNote.repliesCount }}</p>
</button>
<button class="renoteButton" @click="renote()" title="%i18n:@renote%">
%fa:retweet%<p class="count" v-if="appearNote.renoteCount > 0">{{ appearNote.renoteCount }}</p>
<fa icon="retweet"/><p class="count" v-if="appearNote.renoteCount > 0">{{ appearNote.renoteCount }}</p>
</button>
<button class="reactionButton" :class="{ reacted: appearNote.myReaction != null }" @click="react()" ref="reactButton" title="%i18n:@add-reaction%">
%fa:plus%<p class="count" v-if="appearNote.reactions_count > 0">{{ appearNote.reactions_count }}</p>
<fa icon="plus"/><p class="count" v-if="appearNote.reactions_count > 0">{{ appearNote.reactions_count }}</p>
</button>
<button @click="menu()" ref="menuButton">
%fa:ellipsis-h%
<fa icon="ellipsis-h"/>
</button>
</footer>
</div>
@ -190,7 +190,7 @@ export default Vue.extend({
margin 0 8px 0 0
border-radius 6px
[data-fa]
[data-icon]
margin-right 4px
> span

View File

@ -17,8 +17,8 @@
<template v-for="(note, i) in _notes">
<x-note :note="note" :key="note.id" @update:note="onNoteUpdated(i, $event)" ref="note"/>
<p class="date" :key="note.id + '_date'" v-if="i != notes.length - 1 && note._date != _notes[i + 1]._date">
<span>%fa:angle-up%{{ note._datetext }}</span>
<span>%fa:angle-down%{{ _notes[i + 1]._datetext }}</span>
<span><fa icon="angle-up"/>{{ note._datetext }}</span>
<span><fa icon="angle-down"/>{{ _notes[i + 1]._datetext }}</span>
</p>
</template>
</component>
@ -26,7 +26,7 @@
<footer v-if="more">
<button @click="loadMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
<template v-if="!moreFetching">%i18n:@load-more%</template>
<template v-if="moreFetching">%fa:spinner .pulse .fw%</template>
<template v-if="moreFetching"><fa icon="spinner .pulse" fixed-width/></template>
</button>
</footer>
</div>
@ -230,7 +230,7 @@ export default Vue.extend({
span
margin 0 16px
[data-fa]
[data-icon]
margin-right 8px
> .newer-indicator

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