Compare commits

..

133 Commits

Author SHA1 Message Date
syuilo
1915ccabdd 8.26.0 2018-09-05 13:49:08 +09:00
syuilo
6fea2f52f1 nanka iroiro 2018-09-05 13:47:26 +09:00
syuilo
f77eaaa08a Improve usability 2018-09-05 13:06:49 +09:00
syuilo
7c5bc03492 Update langs 2018-09-05 12:53:08 +09:00
syuilo
72a1af6cd4 Merge pull request #2548 from syuilo/l10n_develop
New Crowdin translations
2018-09-05 12:50:11 +09:00
greenkeeper[bot]
4bce6f14f3 fix(package): update node-sass-json-importer to version 4.0.0 (#2614) 2018-09-05 12:48:00 +09:00
greenkeeper[bot]
a38ce86f87 fix(package): update systeminformation to version 3.45.0 (#2609) 2018-09-05 12:47:30 +09:00
greenkeeper[bot]
f539491502 fix(package): update vue-js-modal to version 1.3.26 (#2613) 2018-09-05 12:47:13 +09:00
syuilo
d279f8e9ff 🎨 2018-09-04 19:19:51 +09:00
MeiMei
eaec936fa6 Fix remote follow (#2606) 2018-09-04 18:33:16 +09:00
greenkeeper[bot]
a0735b0e7a fix(package): update webpack to version 4.17.2 (#2599) 2018-09-04 18:15:58 +09:00
MeiMei
5b039a1bee Add User-Agent header (#2602) 2018-09-04 17:44:21 +09:00
syuilo
921609cab1 8.25.0 2018-09-04 13:07:09 +09:00
syuilo
199573ccee #2566 2018-09-04 13:03:16 +09:00
syuilo
977200b7cd 🎨 2018-09-04 12:59:40 +09:00
syuilo
6abff253ea トップページのタイムラインをリアルタイム更新するように 2018-09-04 12:59:34 +09:00
syuilo
ba64de334a Fix bug 2018-09-04 12:58:43 +09:00
syuilo
dc1d7fa9d7 ローカルタイムラインストリームに認証不要で接続できるように 2018-09-04 12:58:35 +09:00
syuilo
f42665d4bc 🎨 2018-09-04 11:34:36 +09:00
syuilo
a5eb19c878 Support darkmode 2018-09-04 11:24:39 +09:00
syuilo
60fa8e13d6 New translations ja-JP.yml (English) 2018-09-04 02:21:29 +09:00
syuilo
ecbaea463b New translations ja-JP.yml (Norwegian) 2018-09-04 02:12:04 +09:00
syuilo
814ddeb436 New translations ja-JP.yml (Dutch) 2018-09-04 02:12:01 +09:00
syuilo
d6466106e8 New translations ja-JP.yml (Japanese, Kansai) 2018-09-04 02:11:59 +09:00
syuilo
633f5384f9 New translations ja-JP.yml (Spanish) 2018-09-04 02:11:56 +09:00
syuilo
fa7989772c New translations ja-JP.yml (Russian) 2018-09-04 02:11:53 +09:00
syuilo
0e395612a6 New translations ja-JP.yml (Portuguese) 2018-09-04 02:11:50 +09:00
syuilo
fb3f52f3ad New translations ja-JP.yml (Polish) 2018-09-04 02:11:48 +09:00
syuilo
ba11c71d65 New translations ja-JP.yml (Korean) 2018-09-04 02:11:46 +09:00
syuilo
bdc3081167 New translations ja-JP.yml (Italian) 2018-09-04 02:11:43 +09:00
syuilo
430efcf1b9 New translations ja-JP.yml (German) 2018-09-04 02:11:41 +09:00
syuilo
996450dd7c New translations ja-JP.yml (French) 2018-09-04 02:11:38 +09:00
syuilo
fa779f0417 New translations ja-JP.yml (English) 2018-09-04 02:11:35 +09:00
syuilo
25cec6d28a New translations ja-JP.yml (Chinese Simplified) 2018-09-04 02:11:33 +09:00
syuilo
c5f8403cea New translations ja-JP.yml (Catalan) 2018-09-04 02:11:30 +09:00
syuilo
a9ae9a65c8 8.24.0 2018-09-04 02:10:47 +09:00
syuilo
3698c679e2 🍕 2018-09-04 02:09:56 +09:00
syuilo
881df20f1b New translations ja-JP.yml (Spanish) 2018-09-03 23:32:05 +09:00
syuilo
7d269c0441 New translations ja-JP.yml (Spanish) 2018-09-03 23:26:23 +09:00
syuilo
ba38f64353 8.23.0 2018-09-03 23:25:35 +09:00
syuilo
db3ae303cb Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2018-09-03 23:23:55 +09:00
syuilo
66f3a155e6 なんかもうめっちゃやった 2018-09-03 23:23:50 +09:00
syuilo
639b483e6c New translations ja-JP.yml (Spanish) 2018-09-03 23:22:57 +09:00
Aya Morisawa
09843a409b Fix typo: Wroker -> Worker (#2597) 2018-09-03 18:58:26 +09:00
syuilo
e894ed5a8b New translations ja-JP.yml (Dutch) 2018-09-03 14:30:56 +09:00
syuilo
d7808299fd New translations ja-JP.yml (Norwegian) 2018-09-03 14:20:56 +09:00
syuilo
f92e0c16d2 New translations ja-JP.yml (Dutch) 2018-09-03 14:20:53 +09:00
syuilo
d94b3757be Merge branch 'master' into develop 2018-09-02 22:41:10 +09:00
syuilo
13e822cba6 Trim text
Closes #2595
2018-09-02 22:40:27 +09:00
Aya Morisawa
c57bf87f52 Make poll button togglable (#2592) 2018-09-02 21:39:47 +09:00
tamaina
99fbd60265 Improve url visual (#2591)
* Use string interpolation

* improve url visual

* fix lint
2018-09-02 20:19:59 +09:00
syuilo
ea9b48db3c Merge branch 'develop' 2018-09-02 19:27:33 +09:00
syuilo
c145c994a9 8.22.0 2018-09-02 19:27:09 +09:00
Acid Chicken (硫酸鶏)
d033998b56 Update README.md [AUTOGEN] (#2586) 2018-09-02 19:10:12 +09:00
Aya Morisawa
3136c714bf Fix users/list/update API (#2590) 2018-09-02 19:03:00 +09:00
Aya Morisawa
c0ee134f19 Add users/lists/delete API (#2589) 2018-09-02 18:59:42 +09:00
syuilo
d15ebe5732 Improve usability 2018-09-02 18:27:43 +09:00
syuilo
ef630195fa モバイルのドライブダイアログがおかしいのを修正 & ダークモード対応 2018-09-02 18:23:47 +09:00
syuilo
e31921151e Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2018-09-02 17:56:39 +09:00
syuilo
f94992abbe 🎨 2018-09-02 17:56:20 +09:00
Aya Morisawa
b00060c09c Clean up 2018-09-02 17:44:49 +09:00
Marihachi
f6217d96d2 add an endpoint users/lists/update (#2585)
* add an endpoint users/lists/update

* add meta params

* fix packing
2018-09-02 11:25:32 +09:00
Acid Chicken (硫酸鶏)
3a6947c7ed Update README.md [AUTOGEN] 2018-09-02 09:45:28 +09:00
syuilo
0fb528ddf8 Merge branch 'develop' 2018-09-02 09:34:26 +09:00
syuilo
14c03f226d 8.21.1 2018-09-02 09:33:55 +09:00
syuilo
4f0d844b43 Remove needless properties 2018-09-02 09:31:11 +09:00
Acid Chicken (硫酸鶏)
b93395fc4c Update README.md [AUTOGEN] 2018-09-02 09:05:34 +09:00
Acid Chicken (硫酸鶏)
34eacb7e2d Update README.md [AUTOGEN] 2018-09-02 08:03:27 +09:00
mei23
0177023ead Use Tombstone for Delete 2018-09-02 08:02:43 +09:00
Aya Morisawa
a4678e45de Not check dependencies 2018-09-02 08:02:10 +09:00
xps2
f24869625e fix 2018-09-02 01:10:55 +09:00
syuilo
01beb705a2 8.21.0 2018-09-02 00:07:23 +09:00
syuilo
ce28c70c35 Clean up 2018-09-01 23:57:05 +09:00
Aya Morisawa
5e0f5c31e7 Merge branch 'string-interpolation' into develop 2018-09-01 23:30:16 +09:00
Aya Morisawa
b28dd4be52 Use typeof 2018-09-01 23:29:22 +09:00
Aya Morisawa
291beb45fc Use string interpolation 2018-09-01 23:12:51 +09:00
tamaina
ffb345ccb5 fix #2315 (#2339)
* improve MFM to html

* improve html to MFM

* missing semicolon

* missing semicolon

* fix html to MFM

タグのリンクは解除するように

* fix bug

* misssing semicolon

* Update html-to-mfm.ts

* Update html-to-mfm.ts
2018-09-01 22:45:27 +09:00
syuilo
d2abe2cd81 Merge pull request #2573 from syuilo/refactor-mfm
Refactor mfm component
2018-09-01 22:39:30 +09:00
Aya Morisawa
acffc3e522 Refactor mfm component 2018-09-01 22:38:50 +09:00
syuilo
0962e62b8c Merge pull request #2572 from syuilo/refactor-reversi-game
Refactor reversi game
2018-09-01 22:20:32 +09:00
Aya Morisawa
91ebd310b7 Refactor reversi game 2018-09-01 22:18:07 +09:00
syuilo
2974c74b4e Merge pull request #2571 from syuilo/refactor-reversi-engine
Refactor reversi engine
2018-09-01 22:11:33 +09:00
Aya Morisawa
3d24112d2d Refactor reversi engine 2018-09-01 22:09:54 +09:00
Aya Morisawa
4a977cd523 Update CHANGELOG.md 2018-09-01 21:42:07 +09:00
syuilo
4b1886990f Merge pull request #2570 from mei23/mei-0901-update2b
Implement ActivityPub Update(Person)
2018-09-01 21:38:49 +09:00
syuilo
f3499b787c 8.20.0 2018-09-01 20:49:06 +09:00
syuilo
5209a584a2 Better post form 2018-09-01 20:47:49 +09:00
mei23
57a63d38aa Send Update activity 2018-09-01 20:23:01 +09:00
mei23
3efffbcf22 Receive Update activity 2018-09-01 20:23:01 +09:00
mei23
15eaebe522 updatePersonで再割り当てを考慮する 2018-09-01 20:23:01 +09:00
mei23
eee98358ac Add missing updatePerson properties 2018-09-01 20:23:01 +09:00
mei23
795fc5e7bc Set Person.updatedAt at first 2018-09-01 20:23:01 +09:00
syuilo
70ac668474 Merge pull request #2568 from syuilo/fix-drop-index
Fix drop index
2018-09-01 19:13:49 +09:00
syuilo
1004e0d6e8 Merge pull request #2567 from syuilo/update-setup-docs
Update setup docs
2018-09-01 19:13:22 +09:00
Aya Morisawa
52aa64fcb6 Fix drop index 2018-09-01 19:12:07 +09:00
Aya Morisawa
7860d97a10 Add type annotation 2018-09-01 18:47:02 +09:00
Aya Morisawa
409b37b271 Update setup docs 2018-09-01 18:42:46 +09:00
Aya Morisawa
ad9b9964fa Update contribution guide 2018-09-01 18:15:25 +09:00
syuilo
d2b5276f43 Merge pull request #2565 from syuilo/contribution-guide
Update contribution guide
2018-09-01 18:06:19 +09:00
Aya Morisawa
7204e2a84c Update contribution guide 2018-09-01 18:05:13 +09:00
syuilo
1377fa3332 Merge pull request #2564 from syuilo/readme
Update README.md
2018-09-01 17:28:13 +09:00
Aya Morisawa
bf087bfccf Update README.md 2018-09-01 17:27:33 +09:00
Aya Morisawa
e846e3d571 Update .npmrc 2018-09-01 16:48:22 +09:00
syuilo
d646e62888 Merge pull request #2559 from acid-chicken/patch-4
Update autogen.sh
2018-09-01 16:34:57 +09:00
Acid Chicken (硫酸鶏)
a228c522f1 Update autogen.sh 2018-09-01 14:54:40 +09:00
syuilo
a951c337b8 New translations ja-JP.yml (English) 2018-09-01 14:30:49 +09:00
syuilo
db3efb3791 New translations ja-JP.yml (English) 2018-09-01 14:20:51 +09:00
syuilo
5f9a9867eb New translations ja-JP.yml (Japanese, Kansai) 2018-09-01 09:51:26 +09:00
syuilo
059a8e07d2 New translations ja-JP.yml (Spanish) 2018-09-01 09:51:24 +09:00
syuilo
cf82f56e66 New translations ja-JP.yml (Russian) 2018-09-01 09:51:20 +09:00
syuilo
2778bd14d4 New translations ja-JP.yml (Portuguese) 2018-09-01 09:51:16 +09:00
syuilo
5b0446739c New translations ja-JP.yml (Polish) 2018-09-01 09:51:14 +09:00
syuilo
55f235d0ac New translations ja-JP.yml (Korean) 2018-09-01 09:51:11 +09:00
syuilo
4ec44c68e9 New translations ja-JP.yml (Italian) 2018-09-01 09:51:09 +09:00
syuilo
e6952d499a New translations ja-JP.yml (German) 2018-09-01 09:51:06 +09:00
syuilo
e0b82f827b New translations ja-JP.yml (French) 2018-09-01 09:51:03 +09:00
syuilo
0bccb17e82 New translations ja-JP.yml (English) 2018-09-01 09:51:00 +09:00
syuilo
b251b8c6a9 New translations ja-JP.yml (Chinese Simplified) 2018-09-01 09:50:58 +09:00
syuilo
c2a62f632b New translations ja-JP.yml (Catalan) 2018-09-01 09:50:56 +09:00
syuilo
37b5afa1a3 New translations ja-JP.yml (English) 2018-09-01 04:52:25 +09:00
syuilo
b80d0a3b12 New translations ja-JP.yml (English) 2018-08-31 16:11:19 +09:00
syuilo
9f60688d37 New translations ja-JP.yml (Japanese, Kansai) 2018-08-30 22:15:42 +09:00
syuilo
ca0ea9e57c New translations ja-JP.yml (Spanish) 2018-08-30 22:15:39 +09:00
syuilo
a77a7e8112 New translations ja-JP.yml (Russian) 2018-08-30 22:15:35 +09:00
syuilo
b26ea2edc0 New translations ja-JP.yml (Portuguese) 2018-08-30 22:15:31 +09:00
syuilo
02b99dfd76 New translations ja-JP.yml (Polish) 2018-08-30 22:15:28 +09:00
syuilo
af02b0f115 New translations ja-JP.yml (Korean) 2018-08-30 22:15:25 +09:00
syuilo
9b3c379678 New translations ja-JP.yml (Italian) 2018-08-30 22:15:21 +09:00
syuilo
a423fd7695 New translations ja-JP.yml (German) 2018-08-30 22:15:18 +09:00
syuilo
de6e1d8c9b New translations ja-JP.yml (French) 2018-08-30 22:15:15 +09:00
syuilo
d9db3e8629 New translations ja-JP.yml (English) 2018-08-30 22:15:13 +09:00
syuilo
ac1c81b7d6 New translations ja-JP.yml (Chinese Simplified) 2018-08-30 22:15:10 +09:00
syuilo
49b2eec534 New translations ja-JP.yml (Catalan) 2018-08-30 22:15:07 +09:00
130 changed files with 3765 additions and 825 deletions

View File

@@ -1,18 +1,19 @@
#!/usr/bin/env bash
# BEARER_TOKEN=
# CAMPAIGN_ID=
# GITHUB_TOKEN=
# HEAD='acid-chicken:patch-autogen'
# REPO='syuilo/misskey'
test "$(curl -LSs -w '\n' -- "https://api.github.com/repos/$REPO/pulls?access_token=$GITHUB_TOKEN" | jq -r '.[].head.label' | grep $HEAD)" && exit 1
# __MISSKEY_BEARER_TOKEN=
# __MISSKEY_CAMPAIGN_ID=
# __MISSKEY_GITHUB_TOKEN=
# __MISSKEY_HEAD=acid-chicken:patch-autogen
# __MISSKEY_REPO=syuilo/misskey
# __MISSKEY_BRANCH=develop
test "$(curl -LSs -w '\n' -- "https://api.github.com/repos/$REPO/pulls?access_token=$__MISSKEY_GITHUB_TOKEN" | jq -r '.[].head.label' | grep $__MISSKEY_HEAD)" && exit 1
cd "$(dirname $0)/.." && \
touch null.cache && \
rm *.cache && \
git checkout master && \
git pull origin master && \
git pull upstream master && \
git checkout $__MISSKEY_BRANCH && \
git pull origin $__MISSKEY_BRANCH && \
git pull upstream $__MISSKEY_BRANCH && \
git stash && \
git rebase -f upstream/master && \
git rebase -f upstream/$__MISSKEY_BRANCH && \
git branch patch-autogen && \
git checkout patch-autogen && \
git reset --hard HEAD || \
@@ -20,12 +21,12 @@ exit 1
touch patreon.md.cache && \
rm patreon.md.cache && \
echo '<!-- PATREON_START -->' > patreon.md.cache && \
URL="https://www.patreon.com/api/oauth2/v2/campaigns/$CAMPAIGN_ID/members?include=currently_entitled_tiers,user&fields%5Btier%5D=title&fields%5Buser%5D=full_name,thumb_url,url,hide_pledges"
url="https://www.patreon.com/api/oauth2/v2/campaigns/$__MISSKEY_CAMPAIGN_ID/members?include=currently_entitled_tiers,user&fields%5Btier%5D=title&fields%5Buser%5D=full_name,thumb_url,url,hide_pledges"
while :
do
touch patreon.raw.cache && \
rm patreon.raw.cache && \
curl -LSs -w '\n' -H "Authorization: Bearer $BEARER_TOKEN" -- $URL > patreon.raw.cache && \
curl -LSs -w '\n' -H "Authorization: Bearer $__MISSKEY_BEARER_TOKEN" -- $url > patreon.raw.cache && \
touch patreon.cache && \
rm patreon.cache && \
cat patreon.raw.cache | \
@@ -42,31 +43,31 @@ while :
xargs -I% echo '<td><a href="%</a></td>' >> patreon.md.cache && \
echo '</tr></table>' >> patreon.md.cache || \
exit 1
NEW_URL="$(cat patreon.raw.cache | jq -r '.links.next')"
test "$NEW_URL" = 'null' && \
new_url="$(cat patreon.raw.cache | jq -r '.links.next')"
test "$new_url" = 'null' && \
break || \
URL="$NEW_URL"
URL="$url"
done
IGNORE= && \
ignore= && \
echo -e "\n**Last updated:** $(date -uR | sed 's/\+0000/UTC/')\n<!-- PATREON_END -->" >> patreon.md.cache && \
touch README.md && \
touch .autogen/README.md && \
rm .autogen/README.md && \
mv README.md .autogen/README.md && \
cat .autogen/README.md | while IFS= read LINE;
cat .autogen/README.md | while IFS= read line;
do
if [[ -z "$IGNORE" ]]
if [[ -z "$ignore" ]]
then
if [[ "$LINE" = '<!-- PATREON_START -->' ]]
if [[ "$line" = '<!-- PATREON_START -->' ]]
then
IGNORE='PATREON_INSIDE'
ignore='PATREON_INSIDE'
else
echo "$LINE" >> README.md
echo "$line" >> README.md
fi
else
if [[ "$LINE" = '<!-- PATREON_END -->' ]]
then
IGNORE=
ignore=
cat patreon.md.cache >> README.md
fi
fi
@@ -80,7 +81,7 @@ test 4 -lt $(cat diff.cache | wc -l) && \
git add README.md && \
git commit -m 'Update README.md [AUTOGEN]' && \
git push -f origin patch-autogen && \
curl -LSs -w '\n' -X POST -d '{"title":"[AUTOMATED] Update README.md","body":"*This pull request was created by a tool.*","head":"'$HEAD'","base":"master"}' -- "https://api.github.com/repos/$REPO/pulls?access_token=$GITHUB_TOKEN"
curl -LSs -w '\n' -X POST -d '{"title":"[AUTOMATED] Update README.md","body":"*This pull request was created by a tool.*","head":"'$__MISSKEY_HEAD'","base":"'$__MISSKEY_BRANCH'"}' -- "https://api.github.com/repos/$__MISSKEY_REPO/pulls?access_token=$__MISSKEY_GITHUB_TOKEN"
git stash
git checkout master
git checkout $__MISSKEY_BRANCH
git branch -D patch-autogen

2
.npmrc
View File

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

View File

@@ -47,13 +47,13 @@ Please run `node cli/migration/5.0.0` before launch.
オセロがリバーシに変更されました。
Othello is now Reversi.
Othello is rename to Reversi.
### Migration
MongoDBの、`othelloGames``othelloMatchings`コレクションをそれぞれ`reversiGames``reversiMatchings`にリネームしてください。
You need to rename `othelloGames` and `othelloMatchings` MongoDB collections to `reversiGames` and `reversiMatchings`.
Please rename `othelloGames` and `othelloMatchings` MongoDB collections to `reversiGames` and `reversiMatchings` respectively.
3.0.0
-----

View File

@@ -1,27 +1,27 @@
# Contribution guide
:v: Misskeyへの貢献ありがとうございます。 :v:
:v: Thanks for your contributions :v:
## Issueの報告
新機能の提案や不具合の報告は https://github.com/syuilo/misskey/issues で管理しています。
Issueを作成する前に、既に同じIssueが作成されていないかご確認ください。
もし既にIssueが作成されている場合は、既存のIssueにコメントをしたりリアクションをするようお願いします。
## Issues
Feature suggestions and bug reports are filed in https://github.com/syuilo/misskey/issues .
Before creating a new issue, please search existing issues to avoid duplication.
If you find the existing issue, please add your reaction or comment to the issue.
## Issueの解決
[pr-welcomeのラベルがついているIssue](https://github.com/syuilo/misskey/labels/pr-welcome)
の解決を目的としたPull Requestを作成してくださると非常にありがたいです。
## Internationalization (i18n)
Please see [Translation guide](./docs/translate.en.md).
## 翻訳の改善
ソースコード中の `%i18n:id%` という形の文字列は、言語ファイルの対応するテキストに置換されます。
言語ファイルは /locales ディレクトリに存在します。
## Localization (l10n)
Please use [Crowdin](https://crowdin.com/project/misskey) for localization.
## ドキュメントの編集
現在Misskeyはドキュメントが大きく不足しています。
ドキュメントは /docs ディレクトリに存在します。
![Crowdin](https://d322cqt584bo4o.cloudfront.net/misskey/localized.svg)
## テストの追加
現在Misskeyはテストが大きく不足しています。
テストコードは /test ディレクトリに存在します。
## Documentation
* Documents for contributors are located in `/docs`.
* Documents for instance admins are located in `/docs`.
* Documents for end users are located in `src/docs`.
## 自動テスト及び自動リリース
Travis CIで行っています。
設定ファイルは /.travis に存在します。
## Test
* Test codes are located in `/test`.
## Continuous integration
Misskey uses Travis for automated test.
Configuration files are located in `/.travis`.

View File

@@ -24,7 +24,7 @@ Why don't you take a short break from the hustle and bustle of the city, and div
* Reactions
* User lists
* Customizable column view (called MisskeyDeck)
* and widgets!
* Customizable widgets
* Private messages
* ActivityPub support
@@ -32,38 +32,25 @@ and more! You can see it with your own eyes at [misskey.xyz](https://misskey.xyz
:package: Create your own instance
----------------------------------------------------------------
If you want to run your own instance of Misskey,
please see [Setup and installation guide](./docs/setup.en.md).
Please see [Setup and installation guide](./docs/setup.en.md).
:wrench: Contribute
:wrench: Contribution
----------------------------------------------------------------
**[PR](https://github.com/syuilo/misskey/pulls)s welcome!**
### i18n
Please see [Translation guide](./docs/translate.en.md).
### l10n
Misskey is using Crowdin for l10n.
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/misskey/localized.svg)](https://crowdin.com/project/misskey)
Please see [Contribution guide](./CONTRIBUTING.md).
:heart: Backers & Sponsors
----------------------------------------------------------------
<!-- PATREON_START -->
<table><tr>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12378075/0156f769e20f412594fa6b87d85fe228/1?token-time=2145916800&token-hash=IsIJRUXszzoD6-7pDnRY8I05T9nSznc4GTaxj7C9SwU%3D" alt="39ff"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12731202/0995c46cdcb54153ab5f073f5869b70a/1?token-time=2145916800&token-hash=Yd60FK_SWfQO56SeiJpy1tDHOnCV4xdEywQe8gn5_Wo%3D" alt="negao"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13099460/43cecdbaa63a40d79bf50a96b9910b9d/1?token-time=2145916800&token-hash=d6P5MWHHsCMxUuBAEPAoVc5wLUR19mIhqAq7Ma9h9rI%3D" alt="ne_moni"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12913507/f7181eacafe8469a93033d85f5969c29/1?token-time=2145916800&token-hash=f03BFb4S2FUx9YEt87TnEmifb4h33OywGBW2akQVtQY%3D" alt="Melilot"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12999811/5f349fafcce44dd1824a8b1ebbec4564/1?token-time=2145916800&token-hash=DVrSdOqQq2dufgNgWZ3XMnEtl_ZAktr8Lhf2tbHKtoA%3D" alt="Axella"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12999811/5f349fafcce44dd1824a8b1ebbec4564/2?token-time=2145916800&token-hash=rwZ8qvbm_kpA4ib3kc07tVKupXeySpY5ATQFGxfL9v0%3D" alt="Axella"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/3384329/8b713330cb27404ea6e9fac50ff96efe/1?token-time=2145916800&token-hash=0eu4-m1gTWA9PhptVZt6rdKcusqcD7RB87rJT23VVFI%3D" alt="べすれい"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12021162/963128bb8d14476dbd8407943db8f31a/1?token-time=2145916800&token-hash=GgJ_NmUB6_nnRNLVGUWjV-WX91On7BOu59LKncYV9fE%3D" alt="gutfuckllc"></td>
<td><img src="https://c8.patreon.com/2/100/12718187" alt="Peter G."></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13039004/509d0c412eb14ae08d6a812a3054f7d6/1?token-time=2145916800&token-hash=zwSu01tOtn5xTUucDZHuPsCxF2HBEMVs9ROJKTlEV_o%3D" alt="nemu"></td>
</tr><tr>
<td><a href="https://www.patreon.com/user?u=12378075">39ff</a></td>
<td><a href="https://www.patreon.com/user?u=12731202">negao</a></td>
<td><a href="https://www.patreon.com/user?u=13099460">ne_moni</a></td>
<td><a href="https://www.patreon.com/user?u=12913507">Melilot</a></td>
@@ -78,20 +65,16 @@ Misskey is using Crowdin for l10n.
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12931605/ead494101f364dffa90efe49e36fb494/1?token-time=2145916800&token-hash=NzSFPjIlodXyv41rwK61aZWVZWfI4surJaNj8vWKvqM%3D" alt="Reiju"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13034746/c711c7f58e204ecfbc2fd646bc8a4eee/1?token-time=2145916800&token-hash=UERBN4OyP7Nh5XwwdDg0N0IE5cD6_qUQMO81Z5Wizso%3D" alt="Hiratake"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/4503830/ccf2cc867ea64de0b524bb2e24b9a1cb/1?token-time=2145916800&token-hash=S1zP0QyLU52Dqq6dtc9qNYyWfW86XrYHiR4NMbeOrnA%3D" alt="dansup"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/4950409/28e7d016209243759d9316be2e21381d/2?token-time=2145916800&token-hash=LuEaDkchH3GQWUcTOhBQ8xfKQYF0s5FjlZRd7Yduia8%3D" alt="mikan54951"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12531784/93a45137841849329ba692da92ac7c60/1?token-time=2145916800&token-hash=tMosUojzUYJCH_3t--tvYA-SMCyrS__hzSndyaRSnbo%3D" alt="Takashi Shibuya"></td>
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12959468/c249e15aebec4424b5c0f427173671b6/1?token-time=2145916800&token-hash=lubpCEdxAkxPlpR2O6bvZ7BIh8Q4nGf-U_mE1qpjVAQ%3D" alt="fujishan"></td>
</tr><tr>
<td><a href="https://www.patreon.com/user?u=5881381">Naoki Kosaka</a></td>
<td><a href="https://www.patreon.com/user?u=12931605">Reiju</a></td>
<td><a href="https://www.patreon.com/hiratake">Hiratake</a></td>
<td><a href="https://www.patreon.com/dansup">dansup</a></td>
<td><a href="https://www.patreon.com/user?u=4950409">mikan54951</a></td>
<td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td>
<td><a href="https://www.patreon.com/fujishan">fujishan</a></td>
</tr></table>
**Last updated:** Sun, 26 Aug 2018 08:55:06 UTC
**Last updated:** Sun, 02 Sep 2018 05:30:06 UTC
<!-- PATREON_END -->
:four_leaf_clover: Copyright

View File

@@ -54,7 +54,7 @@ Please visit https://www.google.com/recaptcha/intro/ and generate keys.
*(optional)* Generating VAPID keys
----------------------------------------------------------------
If you want to enable ServiceWroker, you need to generate VAPID keys:
If you want to enable ServiceWorker, you need to generate VAPID keys:
Unless you have set your global node_modules location elsewhere, you need to run this in root.
``` shell
@@ -131,6 +131,7 @@ You can check if the service is running with `systemctl status misskey`.
2. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)`
3. `npm install`
4. `npm run build`
5. Check [ChangeLog](../CHANGELOG.md) for migration information
----------------------------------------------------------------

View File

@@ -120,6 +120,7 @@ WantedBy=multi-user.target
2. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)`
3. `npm install`
4. `npm run build`
5. [ChangeLog](../CHANGELOG.md)でマイグレーション情報を確認する
----------------------------------------------------------------

View File

@@ -1,5 +1,3 @@
# **Please DO NOT edit these files** except `ja-JP.yml`.
# **DO NOT edit locale files** except `ja-JP.yml`.
If you want to...
* i18n ... please see [Translation guide](../docs/translate.en.md).
* l10n ... please visit https://crowdin.com/project/misskey
Please see [Contribution guide](../CONTRIBUTING.md) for more information.

View File

@@ -87,6 +87,7 @@ common:
use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける"
verified-user: "公式アカウント"
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
reversi:
drawn: "引き分け"
my-turn: "あなたのターンです"
@@ -260,6 +261,8 @@ common/views/components/nav.vue:
develop: "開発者"
feedback: "フィードバック"
common/views/components/note-menu.vue:
detail: "詳細"
copy-link: "リンクをコピー"
favorite: "お気に入り"
pin: "ピン留め"
delete: "削除"
@@ -337,6 +340,9 @@ common/views/components/visibility-chooser.vue:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
common/views/widgets/broadcast.vue:
fetching: "確認中"
no-broadcasts: "お知らせはありません"
@@ -360,8 +366,6 @@ common/views/widgets/posts-monitor.vue:
toggle: "表示を切り替え"
common/views/widgets/hashtags.vue:
title: "ハッシュタグ"
count: "{}人が投稿"
empty: "トレンドなし"
common/views/widgets/server.vue:
title: "サーバー情報"
toggle: "表示を切り替え"

View File

@@ -87,6 +87,7 @@ common:
use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける"
verified-user: "公式アカウント"
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
reversi:
drawn: "引き分け"
my-turn: "あなたのターンです"
@@ -260,6 +261,8 @@ common/views/components/nav.vue:
develop: "Entwickler"
feedback: "Feedback"
common/views/components/note-menu.vue:
detail: "詳細"
copy-link: "リンクをコピー"
favorite: "Diese Anmerkung favorisieren"
pin: "An die Profilseite pinnen"
delete: "Löschen"
@@ -337,6 +340,9 @@ common/views/components/visibility-chooser.vue:
specified: "Direkt"
specified-desc: "Poste nur für bestimmte Benutzer"
private: "Privat"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
common/views/widgets/broadcast.vue:
fetching: "Laden"
no-broadcasts: "Keine Broadcasts"
@@ -360,8 +366,6 @@ common/views/widgets/posts-monitor.vue:
toggle: "表示を切り替え"
common/views/widgets/hashtags.vue:
title: "ハッシュタグ"
count: "{}人が投稿"
empty: "トレンドなし"
common/views/widgets/server.vue:
title: "Serverinformationen"
toggle: "Sicht umschalten"

View File

@@ -84,9 +84,10 @@ common:
my-token-regenerated: "Your token has been regenerated, so you will be signed out."
i-like-sushi: "I prefer sushi rather than pudding"
show-reversi-board-labels: "Show row and column labels in Reversi"
use-contrast-reversi-stones: "Make the stone color clear"
use-contrast-reversi-stones: "Make the stone color clear in reversi"
verified-user: "Verified account"
disable-animated-mfm: "Disable animated texts in a post"
do-not-use-in-production: 'As this is for development, do not use this in production.'
reversi:
drawn: "Draw"
my-turn: "Your turn"
@@ -260,6 +261,8 @@ common/views/components/nav.vue:
develop: "Developers"
feedback: "Feedback"
common/views/components/note-menu.vue:
detail: "Details"
copy-link: "Copy link"
favorite: "Favorite this note"
pin: "Pin to your profile"
delete: "Delete"
@@ -337,6 +340,9 @@ common/views/components/visibility-chooser.vue:
specified: "Direct"
specified-desc: "Post to specified users only"
private: "Private"
common/views/components/trends.vue:
count: "{} users mentioned"
empty: "No popular hashtag trends"
common/views/widgets/broadcast.vue:
fetching: "Fetching"
no-broadcasts: "No announcements"
@@ -360,8 +366,6 @@ common/views/widgets/posts-monitor.vue:
toggle: "Toggle views"
common/views/widgets/hashtags.vue:
title: "Hashtags"
count: "{} users mentioned"
empty: "No popular hashtag trends"
common/views/widgets/server.vue:
title: "Server info"
toggle: "Toggle views"

View File

@@ -11,7 +11,7 @@ common:
warning: "<strong>Misskey no tiene anuncios publicitarios.</strong> Sin embargo, algunas características podrían no estar disponibles si el bloqueador de publicidad está habilitado."
application-authorization: "Autorizaciones de la aplicación."
close: "Cerrar"
do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。"
do-not-copy-paste: "Por favor no copies código aquí. Tu cuenta puede resultar comprometida."
got-it: "¡Listo!"
customization-tips:
title: "Consejos de personalización"
@@ -58,7 +58,7 @@ common:
friday: "Viernes"
saturday: "Sábado"
reactions:
like: "いいね"
like: "Me gusta"
love: "amor"
laugh: "risa"
hmm: "hmm"
@@ -84,9 +84,10 @@ common:
my-token-regenerated: "Tu token se ha regenerado vas a ser desconectado."
i-like-sushi: "Prefiero sushi a pudín"
show-reversi-board-labels: "Mostrar etiquetas de filas y columnas en Reversi"
use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける"
verified-user: "公式アカウント"
use-contrast-reversi-stones: "Hacer el color de la piedra claro en Reversi"
verified-user: "Cuenta verificada"
disable-animated-mfm: "Desactivar texto animado en una publicación"
do-not-use-in-production: 'Esto está en desarrollo, no usarlo para producción.'
reversi:
drawn: "Empatado"
my-turn: "Mi turno"
@@ -170,9 +171,9 @@ common/views/components/games/reversi/reversi.vue:
common/views/components/games/reversi/reversi.game.vue:
surrender: "Rendirse"
surrendered: "Por rendirse"
is-llotheo: "石の少ない方が勝ち(ロセオ)"
looped-map: "ループマップ"
can-put-everywhere: "どこでも置けるモード"
is-llotheo: "El último gana (Llotheo)"
looped-map: "Mapa en bucle"
can-put-everywhere: "Puedes colocar donde quieras"
common/views/components/games/reversi/reversi.index.vue:
title: "Misskey Reversi"
sub-title: "¡Juega Reversi con tus amigos!"
@@ -260,6 +261,8 @@ common/views/components/nav.vue:
develop: "Desarrolladores"
feedback: "Opiniones"
common/views/components/note-menu.vue:
detail: "Detalles"
copy-link: "Copiar enlace"
favorite: "Me gusta esta nota"
pin: "Fijar en el perfil"
delete: "Borrar"
@@ -288,10 +291,10 @@ common/views/components/signin.vue:
signin: "Entra"
or: "O"
signin-with-twitter: "Ingresar con Twitter"
login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。"
login-failed: "Autenticación fallida. Asegúrate de haber usado el nombre de usuario y contraseña correctos."
common/views/components/signup.vue:
invitation-code: "招待コード"
invitation-info: "招待コードをお持ちでない方は、<a href=\"{}\">管理者</a>までご連絡ください。"
invitation-code: "Código de invitación"
invitation-info: "Si no tienes un código de invitación, por favor contacta un <a href=\"{}\">administrador</a>."
username: "Usuario"
checking: "Comprobando..."
available: "Disponible"
@@ -337,6 +340,9 @@ common/views/components/visibility-chooser.vue:
specified: "Directo"
specified-desc: "Publica solo para los seguidores que quieras"
private: "Privada"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
common/views/widgets/broadcast.vue:
fetching: "Recuperando"
no-broadcasts: "Sin emisión"
@@ -360,8 +366,6 @@ common/views/widgets/posts-monitor.vue:
toggle: "Alternar vistas"
common/views/widgets/hashtags.vue:
title: "Etiquetas"
count: "{} usuarios mencionados"
empty: "Ninguna tendencia popular ahora"
common/views/widgets/server.vue:
title: "Información del servidor"
toggle: "Alternar vistas"
@@ -411,7 +415,7 @@ desktop:
uploading-avatar: "Cargando un nuevo avatar"
avatar-updated: "Avatar actualizado"
choose-avatar: "Escoge una imagen de avatar"
invalid-filetype: "この形式のファイルはサポートされていません"
invalid-filetype: "Este tipo de archivo no es compatible aquí"
desktop/views/components/activity.chart.vue:
total: "Negro ... Total"
notes: "Azul ... Notas"
@@ -426,23 +430,23 @@ desktop/views/components/calendar.vue:
next: "Próximo mes"
go: "Click para navegar"
desktop/views/components/charts.vue:
title: "チャート"
per-day: "1日ごと"
per-hour: "1時間ごと"
notes: "投稿"
users: "ユーザー"
drive: "ドライブ"
title: "Gráficos"
per-day: "por día"
per-hour: "por hora"
notes: "Publicaciones"
users: "Usuarios"
drive: "Unidad"
charts:
notes: "投稿の増減 (統合)"
local-notes: "投稿の増減 (ローカル)"
remote-notes: "投稿の増減 (リモート)"
notes-total: "投稿の累計"
users: "ユーザーの増減"
users-total: "ユーザーの累計"
drive: "ドライブ使用量の増減"
drive-total: "ドライブ使用量の累計"
drive-files: "ドライブのファイル数の増減"
drive-files-total: "ドライブのファイル数の累計"
notes: "Número de publicaciones: aumentar/disminuir (Combinado)"
local-notes: "Número de publicaciones: aumentar/disminuir (Local)"
remote-notes: "Número de publicaciones: aumentar/disminuir (Remoto)"
notes-total: "Número de publicaciones: Acumulativo total"
users: "Número de usuarios: aumentar/disminuir"
users-total: "Número de usuarios: Acumulativo total"
drive: "Capacidad de almacenamiento usada: aumentar/disminuir"
drive-total: "Capacidad de almacenamiento usada: Acumulativa total"
drive-files: "Número de archivos almacenados: aumentar/disminuir"
drive-files-total: "Número de archivos almacenados: Acumulativo total"
desktop/views/components/choose-file-from-drive-window.vue:
choose-file: "Escoger archivos"
upload: "Cargar archivos de tu dispositivo"
@@ -463,7 +467,7 @@ desktop/views/components/drive-window.vue:
desktop/views/components/drive.file.vue:
avatar: "Avatar"
banner: "Banner"
nsfw: "閲覧注意"
nsfw: "Ver más"
contextmenu:
rename: "Renombrar"
mark-as-sensitive: "Marcar como 'sensible'"
@@ -515,31 +519,31 @@ desktop/views/components/media-image.vue:
sensitive: "El contenido es NSFW (no seguro para ver en el trabajo, 'not safe for work')"
click-to-show: "Click para mostrar"
desktop/views/components/media-video.vue:
sensitive: "閲覧注意"
click-to-show: "クリックして表示"
sensitive: "Este contenido no es apropiado para ver en el trabajo"
click-to-show: "Click para mostrar"
desktop/views/components/follow-button.vue:
following: "Siguiendo"
follow: "Sigue"
request-pending: "Pendiente de aprobación"
follow-request: "フォロー申請"
follow-request: "Solicitud de seguir"
desktop/views/components/followers-window.vue:
followers: "{} のフォロワー"
followers: "{} seguidores"
desktop/views/components/followers.vue:
empty: "フォロワーはいないようです。"
empty: "Parece que no tienes seguidores aún."
desktop/views/components/following-window.vue:
following: "{} のフォロー"
following: "Siguiendo {}"
desktop/views/components/following.vue:
empty: "フォロー中のユーザーはいないようです。"
empty: "Parece que aún no sigues a nadie."
desktop/views/components/friends-maker.vue:
title: "気になるユーザーをフォロー:"
empty: "おすすめのユーザーは見つかりませんでした。"
fetching: "読み込んでいます"
refresh: "もっと見る"
close: "閉じる"
title: "Usuarios recomendados:"
empty: "No se pudieron encontrar usuarios para recomendar"
fetching: "Cargando"
refresh: "Más"
close: "Cerrar"
desktop/views/components/game-window.vue:
game: "リバーシ"
game: "Reversi"
desktop/views/components/home.vue:
done: "完了"
done: "Listo"
add-widget: "Agregar accesorio:"
add: "Agregar"
desktop/views/input-dialog.vue:
@@ -565,8 +569,8 @@ desktop/views/components/notes.note.vue:
detail: "Mostrar detalles"
private: "Esta publicación es privada"
deleted: "Esta publicación ha sido borrada"
hide: "隠す"
see-more: "もっと見る"
hide: "Esconder"
see-more: "Ver más"
desktop/views/components/notes.vue:
error: "Error al cargar."
retry: "Reintentar"
@@ -602,7 +606,7 @@ desktop/views/components/post-form.vue:
geolocation-alert: "Tu dispositivo no tiene soporte de geolocalización."
error: "Error"
enter-username: "Por favor escribe un nombre de usuario..."
annotations: "内容への注釈 (オプション)"
annotations: "Anotaciones a la publicación (opcional)"
desktop/views/components/post-form-window.vue:
note: "Nota nueva"
reply: "Responder"
@@ -766,40 +770,40 @@ desktop/views/components/timeline.vue:
global: "グローバル"
list: "リスト"
desktop/views/components/ui.header.vue:
welcome-back: "おかえりなさい、"
adjective: "さん"
welcome-back: "Bienvenido/a de vuelta,"
adjective: "-san"
desktop/views/components/ui.header.account.vue:
profile: "プロフィール"
drive: "ドライブ"
favorites: "お気に入り"
lists: "リスト"
follow-requests: "フォロー申請"
customize: "ホームのカスタマイズ"
admin: "管理"
settings: "設定"
signout: "サインアウト"
dark: "闇に飲まれる"
profile: "Tu perfil"
drive: "Unidad"
favorites: "Favoritos"
lists: "Listas"
follow-requests: "Solicitudes de seguimiento"
customize: "Personalizar la página de inicio"
admin: "Admin"
settings: "Configuraciones"
signout: "Desconectarse"
dark: "Sumergirse en la oscuridad"
desktop/views/components/ui.header.nav.vue:
home: "ホーム"
deck: "デッキ"
messaging: "メッセージ"
game: "ゲーム"
home: "Inicio"
deck: "Cubierta"
messaging: "Mensajes"
game: "Juegos"
desktop/views/components/ui.header.notifications.vue:
title: "通知"
title: "Notificaciones"
desktop/views/components/ui.header.post.vue:
post: "新規投稿"
post: "Crear una publicación"
desktop/views/components/ui.header.search.vue:
placeholder: "検索"
placeholder: "Buscar"
desktop/views/components/received-follow-requests-window.vue:
title: "フォロー申請"
accept: "承認"
reject: "拒否"
title: "Solicitudes de seguidores"
accept: "Aceptar"
reject: "Rechazar"
desktop/views/components/user-lists-window.vue:
title: "リスト"
create-list: "リストを作成"
list-name: "リスト名"
title: "Listas de usuario"
create-list: "Crear lista"
list-name: "Nombre de lista"
desktop/views/components/user-preview.vue:
notes: "投稿"
notes: "Publicaciones"
following: "フォロー"
followers: "フォロワー"
desktop/views/components/users-list.vue:

View File

@@ -87,6 +87,7 @@ common:
use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける"
verified-user: "Compte vérifié"
disable-animated-mfm: "Désactiver les textes animés dans les publications"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
reversi:
drawn: "Partie nulle"
my-turn: "Cest votre tour"
@@ -260,6 +261,8 @@ common/views/components/nav.vue:
develop: "Développeur·se·s"
feedback: "Remarques"
common/views/components/note-menu.vue:
detail: "詳細"
copy-link: "リンクをコピー"
favorite: "Mettre cette note en favoris"
pin: "Épingler sur votre profil"
delete: "Supprimer"
@@ -337,6 +340,9 @@ common/views/components/visibility-chooser.vue:
specified: "Direct"
specified-desc: "Publier aux utilisateur·rice·s mentionné·e·s"
private: "Privé"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
common/views/widgets/broadcast.vue:
fetching: "Récupération"
no-broadcasts: "Aucune annonce"
@@ -360,8 +366,6 @@ common/views/widgets/posts-monitor.vue:
toggle: "Basculer entre les vues"
common/views/widgets/hashtags.vue:
title: "Étiquettes"
count: "{} utilisateur·rice·s mentionné·e·s"
empty: "Aucune tendance"
common/views/widgets/server.vue:
title: "Informations sur le serveur"
toggle: "Afficher les vues"

View File

@@ -5,7 +5,7 @@
const fs = require('fs');
const yaml = require('js-yaml');
const langs = ['de-DE', 'en-US', 'fr-FR', 'ja-JP', 'ja-KS', 'pl-PL', 'es-ES'];
const langs = ['de-DE', 'en-US', 'fr-FR', 'ja-JP', 'ja-KS', 'pl-PL', 'es-ES', 'nl-NL'];
const loadLocale = lang => yaml.safeLoad(fs.readFileSync(`${__dirname}/${lang}.yml`, 'utf-8'));
const locales = langs.map(lang => ({ [lang]: loadLocale(lang) }));

View File

@@ -87,6 +87,7 @@ common:
use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける"
verified-user: "公式アカウント"
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
reversi:
drawn: "引き分け"
my-turn: "あなたのターンです"
@@ -260,6 +261,8 @@ common/views/components/nav.vue:
develop: "開発者"
feedback: "フィードバック"
common/views/components/note-menu.vue:
detail: "詳細"
copy-link: "リンクをコピー"
favorite: "お気に入り"
pin: "ピン留め"
delete: "削除"
@@ -337,6 +340,9 @@ common/views/components/visibility-chooser.vue:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
common/views/widgets/broadcast.vue:
fetching: "確認中"
no-broadcasts: "お知らせはありません"
@@ -360,8 +366,6 @@ common/views/widgets/posts-monitor.vue:
toggle: "表示を切り替え"
common/views/widgets/hashtags.vue:
title: "ハッシュタグ"
count: "{}人が投稿"
empty: "トレンドなし"
common/views/widgets/server.vue:
title: "サーバー情報"
toggle: "表示を切り替え"

View File

@@ -375,6 +375,10 @@ common/views/components/visibility-chooser.vue:
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
common/views/widgets/broadcast.vue:
fetching: "確認中"
no-broadcasts: "お知らせはありません"
@@ -403,8 +407,6 @@ common/views/widgets/posts-monitor.vue:
common/views/widgets/hashtags.vue:
title: "ハッシュタグ"
count: "{}人が投稿"
empty: "トレンドなし"
common/views/widgets/server.vue:
title: "サーバー情報"
@@ -1353,6 +1355,9 @@ mobile/views/pages/settings.vue:
post-style: "投稿の表示スタイル"
post-style-standard: "標準"
post-style-smart: "スマート"
notification-position: "通知の表示"
notification-position-bottom: "下"
notification-position-top: "上"
behavior: "動作"
fetch-on-scroll: "スクロールで自動読み込み"
disable-via-mobile: "「モバイルからの投稿」フラグを付けない"

View File

@@ -87,6 +87,7 @@ common:
use-contrast-reversi-stones: "リバーシのアイコンにコントラストをつけんで!"
verified-user: "アメちゃん付きアカウント"
disable-animated-mfm: "投稿内のちょろちょろ動いてんのを止める"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
reversi:
drawn: "おあいこ"
my-turn: "あんさんのターンや"
@@ -260,6 +261,8 @@ common/views/components/nav.vue:
develop: "開発者"
feedback: "フィードバック"
common/views/components/note-menu.vue:
detail: "詳細"
copy-link: "リンクをコピー"
favorite: "お気に入り"
pin: "ピン留め"
delete: "ほかす"
@@ -337,6 +340,9 @@ common/views/components/visibility-chooser.vue:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
common/views/widgets/broadcast.vue:
fetching: "確認中"
no-broadcasts: "お知らせはあらへんで"
@@ -360,8 +366,6 @@ common/views/widgets/posts-monitor.vue:
toggle: "表示を切り替え"
common/views/widgets/hashtags.vue:
title: "ハッシュタグ"
count: "{}人が投稿"
empty: "流行は自分で作るんや"
common/views/widgets/server.vue:
title: "サーバー情報"
toggle: "表示を切り替え"

View File

@@ -87,6 +87,7 @@ common:
use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける"
verified-user: "公式アカウント"
disable-animated-mfm: "게시물의 문자 애니메이션을 비활성화 할"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
reversi:
drawn: "무승부"
my-turn: "당신의 차례입니다"
@@ -260,6 +261,8 @@ common/views/components/nav.vue:
develop: "開発者"
feedback: "フィードバック"
common/views/components/note-menu.vue:
detail: "詳細"
copy-link: "リンクをコピー"
favorite: "お気に入り"
pin: "ピン留め"
delete: "削除"
@@ -337,6 +340,9 @@ common/views/components/visibility-chooser.vue:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
common/views/widgets/broadcast.vue:
fetching: "確認中"
no-broadcasts: "お知らせはありません"
@@ -360,8 +366,6 @@ common/views/widgets/posts-monitor.vue:
toggle: "表示を切り替え"
common/views/widgets/hashtags.vue:
title: "ハッシュタグ"
count: "{}人が投稿"
empty: "トレンドなし"
common/views/widgets/server.vue:
title: "サーバー情報"
toggle: "表示を切り替え"

1241
locales/nl-NL.yml Normal file

File diff suppressed because it is too large Load Diff

1241
locales/no-NO.yml Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -87,6 +87,7 @@ common:
use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける"
verified-user: "公式アカウント"
disable-animated-mfm: "Wyłącz animowany tekst we wpisach"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
reversi:
drawn: "Remis"
my-turn: "Twoja kolej"
@@ -260,6 +261,8 @@ common/views/components/nav.vue:
develop: "Autorzy"
feedback: "Podziel się opinią"
common/views/components/note-menu.vue:
detail: "詳細"
copy-link: "リンクをコピー"
favorite: "Dodaj do ulubionych"
pin: "Przypnij do profilu"
delete: "Usuń"
@@ -337,6 +340,9 @@ common/views/components/visibility-chooser.vue:
specified: "Bezpośredni"
specified-desc: "Tylko dla określonych użytkowników"
private: "Prywatny"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
common/views/widgets/broadcast.vue:
fetching: "Sprawdzanie"
no-broadcasts: "Brak transmisji"
@@ -360,8 +366,6 @@ common/views/widgets/posts-monitor.vue:
toggle: "Przełącz widok"
common/views/widgets/hashtags.vue:
title: "Hashtagi"
count: "Wspomniany przez {} użytkowników"
empty: "Brak popularnych hashtagów"
common/views/widgets/server.vue:
title: "Informacje o serwerze"
toggle: "Przełącz widok"

View File

@@ -87,6 +87,7 @@ common:
use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける"
verified-user: "Conta verificada"
disable-animated-mfm: "Desativar texto animado nas publicações"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
reversi:
drawn: "Empatado"
my-turn: "Seu turno"
@@ -260,6 +261,8 @@ common/views/components/nav.vue:
develop: "開発者"
feedback: "フィードバック"
common/views/components/note-menu.vue:
detail: "詳細"
copy-link: "リンクをコピー"
favorite: "お気に入り"
pin: "ピン留め"
delete: "削除"
@@ -337,6 +340,9 @@ common/views/components/visibility-chooser.vue:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
common/views/widgets/broadcast.vue:
fetching: "確認中"
no-broadcasts: "お知らせはありません"
@@ -360,8 +366,6 @@ common/views/widgets/posts-monitor.vue:
toggle: "表示を切り替え"
common/views/widgets/hashtags.vue:
title: "ハッシュタグ"
count: "{}人が投稿"
empty: "トレンドなし"
common/views/widgets/server.vue:
title: "サーバー情報"
toggle: "表示を切り替え"

View File

@@ -87,6 +87,7 @@ common:
use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける"
verified-user: "公式アカウント"
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
reversi:
drawn: "引き分け"
my-turn: "あなたのターンです"
@@ -260,6 +261,8 @@ common/views/components/nav.vue:
develop: "開発者"
feedback: "フィードバック"
common/views/components/note-menu.vue:
detail: "詳細"
copy-link: "リンクをコピー"
favorite: "お気に入り"
pin: "ピン留め"
delete: "削除"
@@ -337,6 +340,9 @@ common/views/components/visibility-chooser.vue:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
common/views/widgets/broadcast.vue:
fetching: "確認中"
no-broadcasts: "お知らせはありません"
@@ -360,8 +366,6 @@ common/views/widgets/posts-monitor.vue:
toggle: "表示を切り替え"
common/views/widgets/hashtags.vue:
title: "ハッシュタグ"
count: "{}人が投稿"
empty: "トレンドなし"
common/views/widgets/server.vue:
title: "サーバー情報"
toggle: "表示を切り替え"

View File

@@ -87,6 +87,7 @@ common:
use-contrast-reversi-stones: "リバーシのアイコンにコントラストを付ける"
verified-user: "公式アカウント"
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。'
reversi:
drawn: "引き分け"
my-turn: "あなたのターンです"
@@ -260,6 +261,8 @@ common/views/components/nav.vue:
develop: "開発者"
feedback: "フィードバック"
common/views/components/note-menu.vue:
detail: "詳細"
copy-link: "リンクをコピー"
favorite: "お気に入り"
pin: "ピン留め"
delete: "削除"
@@ -337,6 +340,9 @@ common/views/components/visibility-chooser.vue:
specified: "ダイレクト"
specified-desc: "指定したユーザーにのみ公開"
private: "非公開"
common/views/components/trends.vue:
count: "{}人が投稿"
empty: "トレンドなし"
common/views/widgets/broadcast.vue:
fetching: "確認中"
no-broadcasts: "お知らせはありません"
@@ -360,8 +366,6 @@ common/views/widgets/posts-monitor.vue:
toggle: "表示を切り替え"
common/views/widgets/hashtags.vue:
title: "ハッシュタグ"
count: "{}人が投稿"
empty: "トレンドなし"
common/views/widgets/server.vue:
title: "サーバー情報"
toggle: "表示を切り替え"

View File

@@ -1,8 +1,8 @@
{
"name": "misskey",
"author": "syuilo <i@syuilo.com>",
"version": "8.19.1",
"clientVersion": "1.0.9225",
"version": "8.26.0",
"clientVersion": "1.0.9358",
"codename": "nighthike",
"main": "./built/index.js",
"private": true,
@@ -161,7 +161,7 @@
"nan": "2.11.0",
"nested-property": "0.0.7",
"node-sass": "4.9.3",
"node-sass-json-importer": "3.3.1",
"node-sass-json-importer": "4.0.0",
"nprogress": "0.2.0",
"object-assign-deep": "0.4.0",
"on-build-webpack": "0.1.0",
@@ -194,7 +194,7 @@
"stylus": "0.54.5",
"stylus-loader": "3.0.2",
"summaly": "2.2.0",
"systeminformation": "3.44.2",
"systeminformation": "3.45.0",
"syuilo-password-strength": "0.0.1",
"textarea-caret": "3.1.0",
"tmp": "0.0.33",
@@ -210,18 +210,18 @@
"vue": "2.5.17",
"vue-chartjs": "3.4.0",
"vue-cropperjs": "2.2.1",
"vue-js-modal": "1.3.26",
"vue-json-tree-view": "2.1.4",
"vue-loader": "15.4.1",
"vue-router": "3.0.1",
"vue-style-loader": "4.1.2",
"vue-template-compiler": "2.5.17",
"vue-thin-modal": "1.1.1",
"vuedraggable": "2.16.0",
"vuex": "3.0.1",
"vuex-persistedstate": "2.5.4",
"web-push": "3.3.2",
"webfinger.js": "2.6.6",
"webpack": "4.17.1",
"webpack": "4.17.2",
"webpack-cli": "3.1.0",
"websocket": "1.0.26",
"ws": "6.0.0",

View File

@@ -6,6 +6,10 @@ html
&, *
cursor progress !important
html
// iOS
overflow auto
body
overflow-wrap break-word
@@ -126,13 +130,3 @@ pre
[data-fa]
display inline-block
.modal-backdrop
z-index 10000 !important
.modal-content-wrapper
z-index 10001 !important
.modal-content
padding 0 !important
background-color transparent !important

View File

@@ -1,6 +1,3 @@
<template>
<div>
<router-view id="app"></router-view>
<modal-portal/>
</div>
<router-view id="app"></router-view>
</template>

View File

@@ -80,7 +80,7 @@ export default Vue.extend({
accepted() {
this.state = 'accepted';
if (this.session.app.callbackUrl) {
location.href = this.session.app.callbackUrl + '?token=' + this.session.token;
location.href = `${this.session.app.callbackUrl}?token=${this.session.token}`;
}
}
}

View File

@@ -94,7 +94,7 @@
// Get salt query
const salt = localStorage.getItem('salt')
? '?salt=' + localStorage.getItem('salt')
? `?salt=${localStorage.getItem('salt')}`
: '';
// Load an app script

View File

@@ -3,8 +3,10 @@ import MiOS from '../../../../../mios';
export class ReversiGameStream extends Stream {
constructor(os: MiOS, me, game) {
super(os, 'games/reversi-game', {
i: me ? me.token : null,
super(os, 'games/reversi-game', me ? {
i: me.token,
game: game.id
} : {
game: game.id
});
}

View File

@@ -7,9 +7,9 @@ import MiOS from '../../../mios';
*/
export class LocalTimelineStream extends Stream {
constructor(os: MiOS, me) {
super(os, 'local-timeline', {
super(os, 'local-timeline', me ? {
i: me.token
});
} : {});
}
}

View File

@@ -44,11 +44,11 @@ export default class Connection extends EventEmitter {
const query = params
? Object.keys(params)
.map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k]))
.map(k => `${encodeURIComponent(k)}=${encodeURIComponent(params[k])}`)
.join('&')
: null;
this.socket = new ReconnectingWebsocket(`${wsUrl}/${endpoint}${query ? '?' + query : ''}`);
this.socket = new ReconnectingWebsocket(`${wsUrl}/${endpoint}${query ? `?${query}` : ''}`);
this.socket.addEventListener('open', this.onOpen);
this.socket.addEventListener('close', this.onClose);
this.socket.addEventListener('message', this.onMessage);

View File

@@ -125,7 +125,7 @@ export default Vue.extend({
}
if (this.type == 'user') {
const cacheKey = 'autocomplete:user:' + this.q;
const cacheKey = `autocomplete:user:${this.q}`;
const cache = sessionStorage.getItem(cacheKey);
if (cache) {
const users = JSON.parse(cache);
@@ -148,7 +148,7 @@ export default Vue.extend({
this.hashtags = JSON.parse(localStorage.getItem('hashtags') || '[]');
this.fetching = false;
} else {
const cacheKey = 'autocomplete:hashtag:' + this.q;
const cacheKey = `autocomplete:hashtag:${this.q}`;
const cache = sessionStorage.getItem(cacheKey);
if (cache) {
const hashtags = JSON.parse(cache);

View File

@@ -57,7 +57,7 @@ export default Vue.extend({
}
// Check internet connection
fetch('https://google.com?rand=' + Math.random(), {
fetch(`https://google.com?rand=${Math.random()}`, {
mode: 'no-cors'
}).then(() => {
this.internet = true;

View File

@@ -159,11 +159,9 @@ export default Vue.extend({
canPutEverywhere: this.game.settings.canPutEverywhere,
loopedBoard: this.game.settings.loopedBoard
});
this.logs.forEach((log, i) => {
if (i < v) {
this.o.put(log.color, log.pos);
}
});
for (const log of this.logs.slice(0, v)) {
this.o.put(log.color, log.pos);
}
this.$forceUpdate();
}
},

View File

@@ -1,5 +1,6 @@
import Vue from 'vue';
import trends from './trends.vue';
import analogClock from './analog-clock.vue';
import menu from './menu.vue';
import noteHeader from './note-header.vue';
@@ -40,6 +41,7 @@ import uiSelect from './ui/select.vue';
import formButton from './ui/form/button.vue';
import formRadio from './ui/form/radio.vue';
Vue.component('mk-trends', trends);
Vue.component('mk-analog-clock', analogClock);
Vue.component('mk-menu', menu);
Vue.component('mk-note-header', noteHeader);

View File

@@ -1,5 +1,5 @@
<template>
<div class="mk-menu">
<div class="onchrpzrvnoruiaenfcqvccjfuupzzwv">
<div class="backdrop" ref="backdrop" @click="close"></div>
<div class="popover" :class="{ hukidasi }" ref="popover">
<template v-for="item in items">
@@ -119,9 +119,10 @@ export default Vue.extend({
<style lang="stylus" scoped>
@import '~const.styl'
$border-color = rgba(27, 31, 35, 0.15)
root(isDark)
$bg-color = isDark ? #2c303c : #fff
$border-color = rgba(27, 31, 35, 0.15)
.mk-menu
position initial
> .backdrop
@@ -131,14 +132,14 @@ $border-color = rgba(27, 31, 35, 0.15)
z-index 10000
width 100%
height 100%
background rgba(#000, 0.1)
background rgba(#000, isDark ? 0.5 : 0.1)
opacity 0
> .popover
position absolute
z-index 10001
padding 8px 0
background #fff
background $bg-color
border 1px solid $border-color
border-radius 4px
box-shadow 0 3px 12px rgba(27, 31, 35, 0.15)
@@ -172,12 +173,13 @@ $border-color = rgba(27, 31, 35, 0.15)
border-top solid $balloon-size transparent
border-left solid $balloon-size transparent
border-right solid $balloon-size transparent
border-bottom solid $balloon-size #fff
border-bottom solid $balloon-size $bg-color
> button
display block
padding 8px 16px
width 100%
color isDark ? #d6dce2 : #111
&:hover
color $theme-color-foreground
@@ -191,6 +193,12 @@ $border-color = rgba(27, 31, 35, 0.15)
> div
margin 8px 0
height 1px
background #eee
background isDark ? #1c2023 : #eee
.onchrpzrvnoruiaenfcqvccjfuupzzwv[data-darkmode]
root(true)
.onchrpzrvnoruiaenfcqvccjfuupzzwv:not([data-darkmode])
root(false)
</style>

View File

@@ -205,17 +205,8 @@ export default Vue.component('misskey-flavored-markdown', {
}
}));
const _els = [];
els.forEach((el, i) => {
if (el.tag == 'br') {
if (!['div', 'pre'].includes(els[i - 1].tag)) {
_els.push(el);
}
} else {
_els.push(el);
}
});
// el.tag === 'br' のとき i !== 0 が保証されるため、短絡評価により els[i - 1] は配列外参照しない
const _els = els.filter((el, i) => !(el.tag === 'br' && ['div', 'pre'].includes(els[i - 1].tag)));
return createElement('span', _els);
}
});

View File

@@ -78,7 +78,7 @@ export default Vue.extend({
cursor wait !important
> .avatar
margin 16px auto 0 auto
margin 0 auto 0 auto
width 64px
height 64px
background #ddd

View File

@@ -0,0 +1,105 @@
<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>
<!-- トランジションを有効にするとなぜかメモリリークする -->
<!-- <transition-group v-else tag="div" name="chart"> -->
<div>
<div v-for="stat in stats" :key="stat.tag">
<div class="tag">
<router-link :to="`/tags/${ encodeURIComponent(stat.tag) }`" :title="stat.tag">#{{ stat.tag }}</router-link>
<p>{{ '%i18n:@count%'.replace('{}', stat.usersCount) }}</p>
</div>
<x-chart class="chart" :src="stat.chart"/>
</div>
</div>
<!-- </transition-group> -->
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import XChart from './trends.chart.vue';
export default Vue.extend({
components: {
XChart
},
data() {
return {
stats: [],
fetching: true,
clock: null
};
},
mounted() {
this.fetch();
this.clock = setInterval(this.fetch, 1000 * 60);
},
beforeDestroy() {
clearInterval(this.clock);
},
methods: {
fetch() {
(this as any).api('hashtags/trend').then(stats => {
this.stats = stats;
this.fetching = false;
});
}
}
});
</script>
<style lang="stylus" scoped>
root(isDark)
> .fetching
> .empty
margin 0
padding 16px
text-align center
color #aaa
> [data-fa]
margin-right 4px
> div
.chart-move
transition transform 1s ease
> div
display flex
align-items center
padding 14px 16px
&:not(:last-child)
border-bottom solid 1px isDark ? #393f4f : #eee
> .tag
flex 1
overflow hidden
font-size 14px
color isDark ? #9baec8 : #65727b
> a
display block
width 100%
white-space nowrap
overflow hidden
text-overflow ellipsis
color inherit
> p
margin 0
font-size 75%
opacity 0.7
> .chart
height 30px
.csqvmxybqbycalfhkxvyfrgbrdalkaoc[data-darkmode]
root(true)
.csqvmxybqbycalfhkxvyfrgbrdalkaoc:not([data-darkmode])
root(false)
</style>

View File

@@ -24,19 +24,34 @@ export default Vue.extend({
root(isDark)
margin 16px
padding 16px
color isDark ? #fff : #000
background isDark ? #282C37 : #fff
box-shadow 0 3px 1px -2px rgba(#000, 0.2), 0 2px 2px 0 rgba(#000, 0.14), 0 1px 5px 0 rgba(#000, 0.12)
@media (min-width 500px)
padding 32px
> header
font-weight normal
font-size 24px
padding 16px
font-weight bold
font-size 20px
color isDark ? #fff : #444
@media (min-width 500px)
padding 24px 32px
> section
padding 20px 16px
border-top solid 1px isDark ? rgba(#000, 0.3) : rgba(#000, 0.1)
@media (min-width 500px)
padding 32px
&.fit-top
padding-top 0
> header
margin-bottom 16px
font-weight bold
color isDark ? #fff : #444
.ui-card[data-darkmode]
root(true)

View File

@@ -55,7 +55,7 @@ export default Vue.extend({
root(isDark)
display inline-block
margin 32px 32px 32px 0
margin 0 32px 0 0
cursor pointer
transition all 0.3s

View File

@@ -64,6 +64,12 @@ root(isDark)
cursor pointer
transition all 0.3s
&:first-child
margin-top 0
&:last-child
margin-bottom 0
> *
user-select none
@@ -89,6 +95,7 @@ root(isDark)
> .button
display inline-block
flex-shrink 0
margin 3px 0 0 0
width 34px
height 14px

View File

@@ -170,7 +170,7 @@ export default Vue.extend({
return;
}
fetch('/url?url=' + encodeURIComponent(this.url)).then(res => {
fetch(`/url?url=${encodeURIComponent(this.url)}`).then(res => {
res.json().then(info => {
if (info.url == null) return;
this.title = info.title;

View File

@@ -12,6 +12,7 @@
<script lang="ts">
import Vue from 'vue';
import { toUnicode as decodePunycode } from 'punycode';
export default Vue.extend({
props: ['url', 'target'],
data() {
@@ -27,11 +28,11 @@ export default Vue.extend({
created() {
const url = new URL(this.url);
this.schema = url.protocol;
this.hostname = url.hostname;
this.hostname = decodePunycode(url.hostname);
this.port = url.port;
this.pathname = url.pathname;
this.query = url.search;
this.hash = url.hash;
this.pathname = decodeURIComponent(url.pathname);
this.query = decodeURIComponent(url.search);
this.hash = decodeURIComponent(url.hash);
}
});
</script>

View File

@@ -31,15 +31,30 @@ export default Vue.extend({
default: undefined
}
},
data() {
return {
fetching: true,
notes: []
notes: [],
connection: null,
connectionId: null
};
},
mounted() {
this.fetch();
this.connection = (this as any).os.streams.localTimelineStream.getConnection();
this.connectionId = (this as any).os.streams.localTimelineStream.use();
this.connection.on('note', this.onNote);
},
beforeDestroy() {
this.connection.off('note', this.onNote);
(this as any).os.streams.localTimelineStream.dispose(this.connectionId);
},
methods: {
fetch(cb?) {
this.fetching = true;
@@ -49,13 +64,20 @@ export default Vue.extend({
reply: false,
renote: false,
media: false,
poll: false,
bot: false
poll: false
}).then(notes => {
this.notes = notes;
this.fetching = false;
});
}
},
onNote(note) {
if (note.replyId != null) return;
if (note.renoteId != null) return;
if (note.poll != null) return;
this.notes.unshift(note);
},
}
});
</script>

View File

@@ -191,7 +191,7 @@ class Autocomplete {
const acct = renderAcct(value);
// 挿入
this.text = trimmedBefore + '@' + acct + ' ' + after;
this.text = `${trimmedBefore}@${acct} ${after}`;
// キャレットを戻す
this.vm.$nextTick(() => {
@@ -207,7 +207,7 @@ class Autocomplete {
const after = source.substr(caret);
// 挿入
this.text = trimmedBefore + '#' + value + ' ' + after;
this.text = `${trimmedBefore}#${value} ${after}`;
// キャレットを戻す
this.vm.$nextTick(() => {

View File

@@ -1,5 +1,5 @@
import Vue from 'vue';
Vue.filter('notePage', note => {
return '/notes/' + note.id;
return `/notes/${note.id}`;
});

View File

@@ -11,5 +11,5 @@ Vue.filter('userName', user => {
});
Vue.filter('userPage', (user, path?) => {
return '/@' + Vue.filter('acct')(user) + (path ? '/' + path : '');
return `/@${Vue.filter('acct')(user)}${(path ? `/${path}` : '')}`;
});

View File

@@ -1,6 +1,6 @@
<template>
<div class="syxhndwprovvuqhmyvveewmbqayniwkv" v-if="!fetching" :data-darkmode="$store.state.device.darkmode">
<div class="signed-in-as" v-html="'%i18n:@signed-in-as%'.replace('{}', '<b>' + myName + '</b>')"></div>
<div class="signed-in-as" v-html="'%i18n:@signed-in-as%'.replace('{}', `<b>${myName}`)"></div>
<main>
<div class="banner" :style="bannerStyle"></div>
@@ -83,7 +83,7 @@ export default Vue.extend({
userId: this.user.id
});
} else {
if (this.user.isLocked && this.user.hasPendingFollowRequestFromYou) {
if (this.user.hasPendingFollowRequestFromYou) {
this.user = await (this as any).api('following/requests/cancel', {
userId: this.user.id
});

View File

@@ -1,5 +1,5 @@
<template>
<div class="mkw-broadcast"
<div class="anltbovirfeutcigvwgmgxipejaeozxi"
:data-found="broadcasts.length != 0"
:data-melt="props.design == 1"
:data-mobile="platform == 'mobile'"
@@ -25,7 +25,6 @@
<script lang="ts">
import define from '../../../common/define-widget';
import { lang } from '../../../config';
export default define({
name: 'broadcast',
@@ -42,15 +41,7 @@ export default define({
},
mounted() {
(this as any).os.getMeta().then(meta => {
let broadcasts = [];
if (meta.broadcasts) {
meta.broadcasts.forEach(broadcast => {
if (broadcast[lang]) {
broadcasts.push(broadcast[lang]);
}
});
}
this.broadcasts = broadcasts;
this.broadcasts = meta.broadcasts;
this.fetching = false;
});
},
@@ -75,7 +66,7 @@ export default define({
</script>
<style lang="stylus" scoped>
.mkw-broadcast
root(isDark)
padding 10px
border solid 1px #4078c0
border-radius 6px
@@ -142,15 +133,11 @@ export default define({
z-index 1
margin 0
font-size 0.7em
color #555
color isDark ? #fff : #555
&.fetching
text-align center
a
color #555
text-decoration underline
> a
display block
font-size 0.7em
@@ -159,4 +146,10 @@ export default define({
> p
color #fff
.anltbovirfeutcigvwgmgxipejaeozxi[data-darkmode]
root(true)
.anltbovirfeutcigvwgmgxipejaeozxi:not([data-darkmode])
root(false)
</style>

View File

@@ -4,20 +4,7 @@
<template slot="header">%fa:hashtag%%i18n:@title%</template>
<div class="mkw-hashtags--body" :data-mobile="platform == 'mobile'">
<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>
<!-- トランジションを有効にするとなぜかメモリリークする -->
<!-- <transition-group v-else tag="div" name="chart"> -->
<div>
<div v-for="stat in stats" :key="stat.tag">
<div class="tag">
<router-link :to="`/tags/${ encodeURIComponent(stat.tag) }`" :title="stat.tag">#{{ stat.tag }}</router-link>
<p>{{ '%i18n:@count%'.replace('{}', stat.usersCount) }}</p>
</div>
<x-chart class="chart" :src="stat.chart"/>
</div>
</div>
<!-- </transition-group> -->
<mk-trends/>
</div>
</mk-widget-container>
</div>
@@ -25,7 +12,6 @@
<script lang="ts">
import define from '../../../common/define-widget';
import XChart from './hashtags.chart.vue';
export default define({
name: 'hashtags',
@@ -33,89 +19,11 @@ export default define({
compact: false
})
}).extend({
components: {
XChart
},
data() {
return {
stats: [],
fetching: true,
clock: null
};
},
mounted() {
this.fetch();
this.clock = setInterval(this.fetch, 1000 * 60);
},
beforeDestroy() {
clearInterval(this.clock);
},
methods: {
func() {
this.props.compact = !this.props.compact;
this.save();
},
fetch() {
(this as any).api('hashtags/trend').then(stats => {
this.stats = stats;
this.fetching = false;
});
}
}
});
</script>
<style lang="stylus" scoped>
root(isDark)
.mkw-hashtags--body
> .fetching
> .empty
margin 0
padding 16px
text-align center
color #aaa
> [data-fa]
margin-right 4px
> div
.chart-move
transition transform 1s ease
> div
display flex
align-items center
padding 14px 16px
&:not(:last-child)
border-bottom solid 1px isDark ? #393f4f : #eee
> .tag
flex 1
overflow hidden
font-size 14px
color isDark ? #9baec8 : #65727b
> a
display block
width 100%
white-space nowrap
overflow hidden
text-overflow ellipsis
color inherit
> p
margin 0
font-size 75%
opacity 0.7
> .chart
height 30px
.mkw-hashtags[data-darkmode]
root(true)
.mkw-hashtags:not([data-darkmode])
root(false)
</style>

View File

@@ -163,7 +163,7 @@ export default Vue.extend({
});
break;
default:
alert('%i18n:@unhandled-error% ' + err);
alert(`%i18n:@unhandled-error% ${err}`);
}
});
}

View File

@@ -323,7 +323,7 @@ export default Vue.extend({
});
break;
default:
alert('%i18n:@unhandled-error% ' + err);
alert(`%i18n:@unhandled-error% ${err}`);
}
});
}
@@ -404,7 +404,7 @@ export default Vue.extend({
folder: folder
});
} else {
window.open(url + '/i/drive/folder/' + folder.id,
window.open(`${url}/i/drive/folder/${folder.id}`,
'drive_window',
'height=500, width=800');
}

View File

@@ -55,13 +55,15 @@ export default Vue.extend({
methods: {
onFollow(user) {
if (user.id == this.u.id) {
this.user.isFollowing = user.isFollowing;
this.u.isFollowing = user.isFollowing;
this.u.hasPendingFollowRequestFromYou = user.hasPendingFollowRequestFromYou;
}
},
onUnfollow(user) {
if (user.id == this.u.id) {
this.user.isFollowing = user.isFollowing;
this.u.isFollowing = user.isFollowing;
this.u.hasPendingFollowRequestFromYou = user.hasPendingFollowRequestFromYou;
}
},
@@ -74,7 +76,7 @@ export default Vue.extend({
userId: this.u.id
});
} else {
if (this.u.isLocked && this.u.hasPendingFollowRequestFromYou) {
if (this.u.hasPendingFollowRequestFromYou) {
this.u = await (this as any).api('following/requests/cancel', {
userId: this.u.id
});

View File

@@ -48,7 +48,7 @@ export default Vue.extend({
const mouseY = e.clientY - rect.top;
const xp = mouseX / this.$el.offsetWidth * 100;
const yp = mouseY / this.$el.offsetHeight * 100;
this.$el.style.backgroundPosition = xp + '% ' + yp + '%';
this.$el.style.backgroundPosition = `${xp}% ${yp}%`;
this.$el.style.backgroundImage = `url("${this.image.url}")`;
},

View File

@@ -35,7 +35,7 @@
<button class="upload" title="%i18n:@attach-media-from-local%" @click="chooseFile">%fa:upload%</button>
<button class="drive" title="%i18n:@attach-media-from-drive%" @click="chooseFileFromDrive">%fa:cloud%</button>
<button class="kao" title="%i18n:@insert-a-kao%" @click="kao">%fa:R smile%</button>
<button class="poll" title="%i18n:@create-poll%" @click="poll = true">%fa:chart-pie%</button>
<button class="poll" title="%i18n:@create-poll%" @click="poll = !poll">%fa:chart-pie%</button>
<button class="poll" title="%i18n:@hide-contents%" @click="useCw = !useCw">%fa:eye-slash%</button>
<button class="geo" title="%i18n:@attach-location-information%" @click="geo ? removeGeo() : setGeo()">%fa:map-marker-alt%</button>
<button class="visibility" title="%i18n:@visibility%" @click="setVisibility" ref="visibilityButton">
@@ -110,9 +110,9 @@ export default Vue.extend({
computed: {
draftId(): string {
return this.renote
? 'renote:' + this.renote.id
? `renote:${this.renote.id}`
: this.reply
? 'reply:' + this.reply.id
? `reply:${this.reply.id}`
: 'note';
},
@@ -313,7 +313,7 @@ export default Vue.extend({
this.geo = pos.coords;
this.$emit('geo-attached', this.geo);
}, err => {
alert('%i18n:@error%: ' + err.message);
alert(`%i18n:@error%: ${err.message}`);
}, {
enableHighAccuracy: true
});

View File

@@ -0,0 +1,41 @@
<template>
<div class="qldxjjsrseehkusjuoooapmsprvfrxyl mk-admin-card">
<header>%i18n:@announcements%</header>
<textarea v-model="broadcasts"></textarea>
<button class="ui" @click="save">%i18n:@save%</button>
</div>
</template>
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
data() {
return {
broadcasts: '',
};
},
created() {
(this as any).os.getMeta().then(meta => {
this.broadcasts = JSON.stringify(meta.broadcasts, null, ' ');
});
},
methods: {
save() {
(this as any).api('admin/update-meta', {
broadcasts: JSON.parse(this.broadcasts)
});
}
}
});
</script>
<style lang="stylus" scoped>
@import '~const.styl'
.qldxjjsrseehkusjuoooapmsprvfrxyl
textarea
width 100%
min-height 300px
</style>

View File

@@ -4,6 +4,7 @@
<ul>
<li @click="nav('dashboard')" :class="{ active: page == 'dashboard' }">%fa:chalkboard .fw%%i18n:@dashboard%</li>
<li @click="nav('users')" :class="{ active: page == 'users' }">%fa:users .fw%%i18n:@users%</li>
<li @click="nav('announcements')" :class="{ active: page == 'announcements' }">%fa:broadcast-tower .fw%%i18n:@announcements%</li>
<!-- <li @click="nav('drive')" :class="{ active: page == 'drive' }">%fa:cloud .fw%%i18n:@drive%</li> -->
<!-- <li @click="nav('update')" :class="{ active: page == 'update' }">%i18n:@update%</li> -->
</ul>
@@ -13,6 +14,9 @@
<x-dashboard/>
<x-charts/>
</div>
<div v-show="page == 'announcements'">
<x-announcements/>
</div>
<div v-if="page == 'users'">
<x-suspend-user/>
<x-unsuspend-user/>
@@ -28,6 +32,7 @@
<script lang="ts">
import Vue from "vue";
import XDashboard from "./admin.dashboard.vue";
import XAnnouncements from "./admin.announcements.vue";
import XSuspendUser from "./admin.suspend-user.vue";
import XUnsuspendUser from "./admin.unsuspend-user.vue";
import XVerifyUser from "./admin.verify-user.vue";
@@ -37,6 +42,7 @@ import XCharts from "../../components/charts.vue";
export default Vue.extend({
components: {
XDashboard,
XAnnouncements,
XSuspendUser,
XUnsuspendUser,
XVerifyUser,

View File

@@ -31,7 +31,7 @@ export default Vue.extend({
const title = folder.name + ' | %i18n:@title%';
// Rewrite URL
history.pushState(null, title, '/i/drive/folder/' + folder.id);
history.pushState(null, title, `/i/drive/folder/${folder.id}`);
document.title = title;
}

View File

@@ -16,10 +16,10 @@ export default Vue.extend({
methods: {
nav(game, actualNav) {
if (actualNav) {
this.$router.push('/reversi/' + game.id);
this.$router.push(`/reversi/${game.id}`);
} else {
// TODO: https://github.com/vuejs/vue-router/issues/703
this.$router.push('/reversi/' + game.id);
this.$router.push(`/reversi/${game.id}`);
}
}
}

View File

@@ -46,7 +46,7 @@ export default Vue.extend({
this.user = user;
this.fetching = false;
document.title = 'メッセージ: ' + getUserName(this.user);
document.title = `メッセージ: ${getUserName(this.user)}`;
Progress.done();
});

View File

@@ -1,48 +1,60 @@
<template>
<div class="mk-welcome">
<img ref="pointer" class="pointer" src="/assets/pointer.png" alt="">
<button @click="dark">
<template v-if="$store.state.device.darkmode">%fa:moon%</template>
<template v-else>%fa:R moon%</template>
</button>
<mk-forkit class="forkit"/>
<div class="body">
<div class="container">
<div class="main block">
<h1 v-if="name != 'Misskey'">{{ name }}</h1>
<h1 v-else><img :src="$store.state.device.darkmode ? 'assets/title.dark.svg' : 'assets/title.light.svg'" :alt="name"></h1>
<div class="info">
<span><b>{{ host }}</b></span>
<span><b>{{ host }}</b> - <span v-html="'%i18n:@powered-by-misskey%'"></span></span>
<span class="stats" v-if="stats">
<span>%fa:user% {{ stats.originalUsersCount | number }}</span>
<span>%fa:pencil-alt% {{ stats.originalNotesCount | number }}</span>
</span>
</div>
<main>
<div class="about">
<h1 v-if="name != 'Misskey'">{{ name }}</h1>
<h1 v-else><img :src="$store.state.device.darkmode ? 'assets/title.dark.svg' : 'assets/title.light.svg'" :alt="name"></h1>
<p class="powerd-by" v-if="name != 'Misskey'" v-html="'%i18n:@powered-by-misskey%'"></p>
<p class="desc" v-html="description || '%i18n:common.about%'"></p>
<a ref="signup" @click="signup">📦 %i18n:@signup%</a>
</div>
<div class="login">
<mk-signin/>
</div>
</main>
<div class="hashtags">
<router-link v-for="tag in tags" :key="tag" :to="`/tags/${ tag }`" :title="tag">#{{ tag }}</router-link>
<p class="desc" v-html="description || '%i18n:common.about%'"></p>
<p class="sign">
<span class="signup" @click="signup">%i18n:@signup%</span>
<span class="divider">|</span>
<span class="signin" @click="signin">%i18n:@signin%</span>
</p>
</div>
<div class="broadcasts block">
<div v-for="broadcast in broadcasts">
<h1 v-html="broadcast.title"></h1>
<div v-html="broadcast.text"></div>
</div>
</div>
<div class="nav block">
<mk-nav class="nav"/>
</div>
<mk-forkit class="forkit"/>
<img src="assets/title.dark.svg" :alt="name">
</div>
<div class="tl">
<mk-welcome-timeline :max="20"/>
<div class="side">
<mk-trends class="trends block"/>
<mk-welcome-timeline class="tl block" :max="20"/>
</div>
</div>
<modal name="signup">
<div :class="$style.modal">
<header :class="$style.signupFormHeader">%i18n:@signup%</header>
<mk-signup :class="$style.signupForm"/>
</div>
<modal name="signup" :class="$store.state.device.darkmode ? 'modal-dark' : 'modal-light'" width="450px" height="auto" scrollable>
<header class="formHeader">%i18n:@signup%</header>
<mk-signup class="form"/>
</modal>
<modal name="signin" :class="$store.state.device.darkmode ? 'modal-dark' : 'modal-light'" width="450px" height="auto" scrollable>
<header class="formHeader">%i18n:@signin%</header>
<mk-signin class="form"/>
</modal>
</div>
</template>
@@ -59,42 +71,27 @@ export default Vue.extend({
host,
name: 'Misskey',
description: '',
pointerInterval: null,
tags: []
broadcasts: []
};
},
created() {
(this as any).os.getMeta().then(meta => {
this.name = meta.name;
this.description = meta.description;
this.broadcasts = meta.broadcasts;
});
(this as any).api('stats').then(stats => {
this.stats = stats;
});
(this as any).api('hashtags/trend').then(stats => {
this.tags = stats.map(x => x.tag);
});
},
mounted() {
this.point();
this.pointerInterval = setInterval(this.point, 100);
},
beforeDestroy() {
clearInterval(this.pointerInterval);
},
methods: {
point() {
const x = this.$refs.signup.getBoundingClientRect();
this.$refs.pointer.style.top = x.top + x.height + 'px';
this.$refs.pointer.style.left = x.left + 'px';
},
signup() {
this.$modal.push('signup');
this.$modal.show('signup');
},
signin() {
this.$modal.push('signin');
this.$modal.show('signin');
},
dark() {
this.$store.commit('device/set', {
@@ -106,11 +103,40 @@ export default Vue.extend({
});
</script>
<style>
#wait {
right: auto;
left: 15px;
}
<style lang="stylus">
#wait
right auto
left 15px
.v--modal-overlay
background rgba(0, 0, 0, 0.6)
.modal-light
.v--modal-box
color #777
.formHeader
border-bottom solid 1px #eee
.modal-dark
.v--modal-box
background #313543
color #fff
.formHeader
border-bottom solid 1px rgba(#000, 0.2)
.modal-light
.modal-dark
.form
padding 24px 48px 48px 48px
.formHeader
text-align center
padding 48px 0 12px 0
margin 0 48px
font-size 1.5em
</style>
<style lang="stylus" scoped>
@@ -119,122 +145,87 @@ export default Vue.extend({
root(isDark)
display flex
min-height 100vh
//background-color #00070F
//background-image url('/assets/bg.jpg')
//background-position center
//background-size cover
> .pointer
display block
> .forkit
position absolute
z-index 1
top 0
right 0
width 180px
margin 0 0 0 -180px
transform rotateY(180deg) translateX(-10px) translateY(-48px)
pointer-events none
> button
position fixed
z-index 1
top 0
left 0
bottom 16px
left 16px
padding 16px
font-size 18px
color #fff
display none // TODO
color isDark ? #fff : #444
> .body
flex 1
padding 64px 0 0 0
text-align center
background #578394
background-position center
background-size cover
display grid
grid-template-rows 0.5fr 0.5fr 64px
grid-template-columns 1fr 350px
gap 16px
width 100%
max-width 1200px
height 100vh
min-height 800px
margin 0 auto
padding 64px
&:before
content ''
display block
position absolute
top 0
left 0
right 0
bottom 0
background rgba(#000, 0.5)
.block
color isDark ? #fff : #444
background isDark ? #313543 : #fff
box-shadow 0 3px 8px rgba(0, 0, 0, 0.2)
//border-radius 8px
overflow auto
> .forkit
position absolute
top 0
right 0
> .main
grid-row 1
grid-column 1
padding 32px
border-top solid 5px $theme-color
> img
position absolute
bottom 16px
right 16px
width 150px
> h1
margin 0
> .container
$aboutWidth = 380px
$loginWidth = 340px
$width = $aboutWidth + $loginWidth
> img
margin -8px 0 0 -16px
max-width 280px
> .info
margin 0 auto 16px auto
width $width
font-size 14px
color #fff
> .stats
margin-left 16px
padding-left 16px
border-left solid 1px #fff
border-left solid 1px isDark ? #fff : #444
> *
margin-right 16px
> main
display flex
margin auto
width $width
border-radius 8px
overflow hidden
box-shadow 0 2px 8px rgba(#000, 0.3)
> .sign
font-size 120%
> .about
width $aboutWidth
color #444
background #fff
> .divider
margin 0 16px
> h1
margin 0 0 16px 0
padding 32px 32px 0 32px
color #444
> .signin
> .signup
cursor pointer
> img
width 170px
vertical-align bottom
> .powerd-by
margin 16px
opacity 0.7
> .desc
margin 0
padding 0 32px 16px 32px
> a
display inline-block
margin 0 0 32px 0
font-weight bold
> .login
width $loginWidth
padding 16px 32px 32px 32px
background isDark ? #2e3440 : #f5f5f5
&:hover
color $theme-color
> .hashtags
margin 16px auto
width $width
font-size 14px
color #fff
background rgba(#000, 0.3)
border-radius 8px
@@ -242,22 +233,47 @@ root(isDark)
display inline-block
margin 14px
> .nav
display block
margin 16px 0
font-size 14px
color #fff
> .broadcasts
grid-row 2
grid-column 1
padding 32px
> .tl
margin 0
width 410px
height 100vh
text-align left
background isDark ? #313543 : #fff
> div
padding 0 0 16px 0
margin 0 0 16px 0
border-bottom 1px solid isDark ? rgba(#000, 0.2) : rgba(#000, 0.05)
> *
max-height 100%
overflow auto
> h1
margin 0
font-size 1.5em
> .nav
display flex
justify-content center
align-items center
grid-row 3
grid-column 1
font-size 14px
> .side
display grid
grid-row 1 / 4
grid-column 2
grid-template-rows 1fr 350px
grid-template-columns 1fr
gap 16px
> .tl
grid-row 1
grid-column 1
text-align left
max-height 100%
overflow auto
> .trends
grid-row 2
grid-column 1
padding 8px
.mk-welcome[data-darkmode]
root(true)
@@ -266,33 +282,3 @@ root(isDark)
root(false)
</style>
<style lang="stylus" module>
.modal
width 500px
background #fff !important
.signupForm
padding 24px 48px 48px 48px
.signupFormHeader
padding 48px 0 12px 0
margin: 0 48px
font-size 1.5em
color #777
border-bottom solid 1px #eee
.signinForm
padding 24px 48px 48px 48px
.signinFormHeader
padding 48px 0 12px 0
margin: 0 48px
font-size 1.5em
color #777
border-bottom solid 1px #eee
.nav
a
color #666
</style>

View File

@@ -10,8 +10,7 @@ import VAnimateCss from 'v-animate-css';
import Element from 'element-ui';
import ElementLocaleEn from 'element-ui/lib/locale/lang/en';
import ElementLocaleJa from 'element-ui/lib/locale/lang/ja';
import VueThinModal from 'vue-thin-modal';
import 'vue-thin-modal/dist/vue-thin-modal.css';
import VModal from 'vue-js-modal';
import App from './app.vue';
import checkForUpdate from './common/scripts/check-for-update';
@@ -30,9 +29,7 @@ Vue.use(VueRouter);
Vue.use(TreeView);
Vue.use(VAnimateCss);
Vue.use(Element, { locale: elementLocale });
Vue.use(VueThinModal, {
autoMountPortal: false
});
Vue.use(VModal);
// Register global directives
require('./common/views/directives');

View File

@@ -3,7 +3,7 @@ import { EventEmitter } from 'eventemitter3';
import * as uuid from 'uuid';
import initStore from './store';
import { apiUrl, swPublickey, version, lang, googleMapsApiKey } from './config';
import { apiUrl, version, lang } from './config';
import Progress from './common/scripts/loading';
import Connection from './common/scripts/streaming/stream';
import { HomeStreamManager } from './common/scripts/streaming/home';
@@ -230,13 +230,13 @@ export default class MiOS extends EventEmitter {
//#region Init stream managers
this.streams.serverStatsStream = new ServerStatsStreamManager(this);
this.streams.notesStatsStream = new NotesStatsStreamManager(this);
this.streams.localTimelineStream = new LocalTimelineStreamManager(this, this.store.state.i);
this.once('signedin', () => {
// Init home stream manager
this.stream = new HomeStreamManager(this, this.store.state.i);
// Init other stream manager
this.streams.localTimelineStream = new LocalTimelineStreamManager(this, this.store.state.i);
this.streams.hybridTimelineStream = new HybridTimelineStreamManager(this, this.store.state.i);
this.streams.globalTimelineStream = new GlobalTimelineStreamManager(this, this.store.state.i);
this.streams.driveStream = new DriveStreamManager(this, this.store.state.i);
@@ -361,7 +361,7 @@ export default class MiOS extends EventEmitter {
// A public key your push server will use to send
// messages to client apps via a push server.
applicationServerKey: urlBase64ToUint8Array(swPublickey)
applicationServerKey: urlBase64ToUint8Array(this.meta.data.swPublickey)
};
// Subscribe push notification

View File

@@ -0,0 +1,23 @@
import PostForm from '../views/components/post-form-dialog.vue';
export default (os) => (opts) => {
const o = opts || {};
document.documentElement.style.overflow = 'hidden';
function recover() {
document.documentElement.style.overflow = 'auto';
}
const vm = new PostForm({
parent: os.app,
propsData: {
reply: o.reply,
renote: o.renote
}
}).$mount();
vm.$once('cancel', recover);
vm.$once('posted', recover);
document.body.appendChild(vm.$el);
(vm as any).focus();
};

View File

@@ -14,6 +14,7 @@ import chooseDriveFolder from './api/choose-drive-folder';
import chooseDriveFile from './api/choose-drive-file';
import dialog from './api/dialog';
import input from './api/input';
import post from './api/post';
import notify from './api/notify';
import MkIndex from './views/pages/index.vue';
@@ -90,7 +91,7 @@ init((launch) => {
chooseDriveFile,
dialog: dialog(os),
input,
post: () => alert('deprecated'),
post: post(os),
notify
}));
}, true);

View File

@@ -1,12 +1,12 @@
<template>
<div class="mk-drive-file-chooser">
<div class="cdxzvcfawjxdyxsekbxbfgtplebnoneb">
<div class="body">
<header>
<h1>%i18n:@select-file%<span class="count" v-if="files.length > 0">({{ files.length }})</span></h1>
<button class="close" @click="cancel">%fa:times%</button>
<button v-if="multiple" class="ok" @click="ok">%fa:check%</button>
</header>
<mk-drive ref="browser"
<mk-drive class="drive" ref="browser"
:select-file="true"
:multiple="multiple"
@change-selection="onChangeSelection"
@@ -46,7 +46,7 @@ export default Vue.extend({
</script>
<style lang="stylus" scoped>
.mk-drive-file-chooser
root(isDark)
position fixed
z-index 20000
top 0
@@ -59,10 +59,11 @@ export default Vue.extend({
> .body
width 100%
height 100%
background #fff
background isDark ? #282c37 : #fff
> header
border-bottom solid 1px #eee
border-bottom solid 1px isDark ? #1b1f29 : #eee
color isDark ? #fff : #111
> h1
margin 0
@@ -90,9 +91,15 @@ export default Vue.extend({
line-height 42px
width 42px
> .mk-drive
> .drive
height calc(100% - 42px)
overflow scroll
-webkit-overflow-scrolling touch
.cdxzvcfawjxdyxsekbxbfgtplebnoneb[data-darkmode]
root(true)
.cdxzvcfawjxdyxsekbxbfgtplebnoneb:not([data-darkmode])
root(false)
</style>

View File

@@ -48,12 +48,14 @@ export default Vue.extend({
onFollow(user) {
if (user.id == this.u.id) {
this.u.isFollowing = user.isFollowing;
this.u.hasPendingFollowRequestFromYou = user.hasPendingFollowRequestFromYou;
}
},
onUnfollow(user) {
if (user.id == this.u.id) {
this.u.isFollowing = user.isFollowing;
this.u.hasPendingFollowRequestFromYou = user.hasPendingFollowRequestFromYou;
}
},
@@ -66,7 +68,7 @@ export default Vue.extend({
userId: this.u.id
});
} else {
if (this.u.isLocked && this.u.hasPendingFollowRequestFromYou) {
if (this.u.hasPendingFollowRequestFromYou) {
this.u = await (this as any).api('following/requests/cancel', {
userId: this.u.id
});

View File

@@ -75,19 +75,11 @@
<div class="replies" v-if="!compact">
<x-sub v-for="note in replies" :key="note.id" :note="note"/>
</div>
<modal :name="replyFormId">
<mk-post-form @posted="replyFormClosed" @cancel="replyFormClosed" :reply="p"/>
</modal>
<modal :name="renoteFormId">
<mk-post-form @posted="renoteFormClosed" @cancel="renoteFormClosed" :renote="p"/>
</modal>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import * as uuid from 'uuid';
import parse from '../../../../../mfm/parse';
import MkNoteMenu from '../../../common/views/components/note-menu.vue';
@@ -113,9 +105,7 @@ export default Vue.extend({
return {
conversation: [],
conversationFetching: false,
replies: [],
replyFormId: uuid(),
renoteFormId: uuid()
replies: []
};
},
@@ -195,19 +185,15 @@ export default Vue.extend({
},
reply() {
this.$modal.push(this.replyFormId);
},
replyFormClosed() {
this.$modal.pop();
(this as any).apis.post({
reply: this.p
});
},
renote() {
this.$modal.push(this.renoteFormId);
},
renoteFormClosed() {
this.$modal.pop();
(this as any).apis.post({
renote: this.p
});
},
react() {

View File

@@ -60,19 +60,11 @@
</footer>
</div>
</article>
<modal :name="replyFormId">
<mk-post-form @posted="replyFormClosed" @cancel="replyFormClosed" :reply="p"/>
</modal>
<modal :name="renoteFormId">
<mk-post-form @posted="renoteFormClosed" @cancel="renoteFormClosed" :renote="p"/>
</modal>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import * as uuid from 'uuid';
import parse from '../../../../../mfm/parse';
import MkNoteMenu from '../../../common/views/components/note-menu.vue';
@@ -90,9 +82,7 @@ export default Vue.extend({
return {
showContent: false,
connection: null,
connectionId: null,
replyFormId: uuid(),
renoteFormId: uuid()
connectionId: null
};
},
@@ -205,19 +195,15 @@ export default Vue.extend({
},
reply() {
this.$modal.push(this.replyFormId);
},
replyFormClosed() {
this.$modal.pop();
(this as any).apis.post({
reply: this.p
});
},
renote() {
this.$modal.push(this.renoteFormId);
},
renoteFormClosed() {
this.$modal.pop();
(this as any).apis.post({
renote: this.p
});
},
react() {
@@ -485,10 +471,6 @@ root(isDark)
&.reacted
color $theme-color
&.menu
@media (max-width 350px)
display none
.note[data-darkmode]
root(true)

View File

@@ -1,6 +1,8 @@
<template>
<div class="mk-notify">
<mk-notification-preview :notification="notification"/>
<div class="mk-notify" :class="pos">
<div>
<mk-notification-preview :notification="notification"/>
</div>
</div>
</template>
@@ -10,11 +12,16 @@ import * as anime from 'animejs';
export default Vue.extend({
props: ['notification'],
computed: {
pos() {
return this.$store.state.device.mobileNotificationPosition;
}
},
mounted() {
this.$nextTick(() => {
anime({
targets: this.$el,
bottom: '0px',
[this.pos]: '0px',
duration: 500,
easing: 'easeOutQuad'
});
@@ -22,7 +29,7 @@ export default Vue.extend({
setTimeout(() => {
anime({
targets: this.$el,
bottom: '-64px',
[this.pos]: `-${this.$el.offsetHeight}px`,
duration: 500,
easing: 'easeOutQuad',
complete: () => this.$destroy()
@@ -35,15 +42,32 @@ export default Vue.extend({
<style lang="stylus" scoped>
.mk-notify
$height = 78px
position fixed
z-index 1024
bottom -64px
left 0
right 0
width 100%
height 64px
max-width 500px
height $height
margin 0 auto
padding 8px
pointer-events none
-webkit-backdrop-filter blur(2px)
backdrop-filter blur(2px)
background-color rgba(#000, 0.5)
font-size 80%
&.bottom
bottom -($height)
&.top
top -($height)
> div
height 100%
-webkit-backdrop-filter blur(2px)
backdrop-filter blur(2px)
background-color rgba(#000, 0.5)
border-radius 7px
overflow hidden
</style>

View File

@@ -0,0 +1,126 @@
<template>
<div class="ulveipglmagnxfgvitaxyszerjwiqmwl">
<div class="bg" ref="bg"></div>
<div class="main" ref="main">
<mk-post-form ref="form"
:reply="reply"
:renote="renote"
:initial-text="initialText"
:instant="instant"
@posted="onPosted"
@cancel="onCanceled"/>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import * as anime from 'animejs';
export default Vue.extend({
props: {
reply: {
type: Object,
required: false
},
renote: {
type: Object,
required: false
},
initialText: {
type: String,
required: false
},
instant: {
type: Boolean,
required: false,
default: false
}
},
mounted() {
this.$nextTick(() => {
(this.$refs.bg as any).style.pointerEvents = 'auto';
anime({
targets: this.$refs.bg,
opacity: 1,
duration: 100,
easing: 'linear'
});
anime({
targets: this.$refs.main,
opacity: 1,
translateY: [-16, 0],
duration: 300,
easing: 'easeOutQuad'
});
});
},
methods: {
focus() {
this.$refs.form.focus();
},
close() {
(this.$refs.bg as any).style.pointerEvents = 'none';
anime({
targets: this.$refs.bg,
opacity: 0,
duration: 300,
easing: 'linear'
});
(this.$refs.main as any).style.pointerEvents = 'none';
anime({
targets: this.$refs.main,
opacity: 0,
translateY: 16,
duration: 300,
easing: 'easeOutQuad',
complete: () => this.$destroy()
});
},
onPosted() {
this.$emit('posted');
this.close();
},
onCanceled() {
this.$emit('cancel');
this.close();
}
}
});
</script>
<style lang="stylus" scoped>
.ulveipglmagnxfgvitaxyszerjwiqmwl
> .bg
display block
position fixed
z-index 10000
top 0
left 0
width 100%
height 100%
background rgba(#000, 0.7)
opacity 0
pointer-events none
> .main
display block
position fixed
z-index 10000
top 0
left 0
right 0
height 100%
overflow auto
margin 0 auto 0 auto
opacity 0
transform translateY(-16px)
</style>

View File

@@ -105,9 +105,9 @@ export default Vue.extend({
computed: {
draftId(): string {
return this.renote
? 'renote:' + this.renote.id
? `renote:${this.renote.id}`
: this.reply
? 'reply:' + this.reply.id
? `reply:${this.reply.id}`
: 'note';
},
@@ -229,7 +229,7 @@ export default Vue.extend({
navigator.geolocation.getCurrentPosition(pos => {
this.geo = pos.coords;
}, err => {
alert('%i18n:@error%: ' + err.message);
alert(`%i18n:@error%: ${err.message}`);
}, {
enableHighAccuracy: true
});

View File

@@ -82,7 +82,7 @@ export default Vue.extend({
search() {
const query = window.prompt('%i18n:@search%');
if (query == null || query == '') return;
this.$router.push('/search?q=' + encodeURIComponent(query));
this.$router.push(`/search?q=${encodeURIComponent(query)}`);
},
onReversiInvited() {
this.hasGameInvitation = true;

View File

@@ -80,7 +80,7 @@ export default Vue.extend({
if (!silent) {
// Rewrite URL
history.pushState(null, title, '/i/drive/folder/' + folder.id);
history.pushState(null, title, `/i/drive/folder/${folder.id}`);
}
document.title = title;
@@ -93,7 +93,7 @@ export default Vue.extend({
if (!silent) {
// Rewrite URL
history.pushState(null, title, '/i/drive/file/' + file.id);
history.pushState(null, title, `/i/drive/file/${file.id}`);
}
document.title = title;

View File

@@ -49,7 +49,7 @@ export default Vue.extend({
this.user = user;
this.fetching = false;
document.title = '%i18n:@followers-of%'.replace('{}', this.name) + ' | ' + (this as any).os.instanceName;
document.title = `${'%i18n:@followers-of%'.replace('{}', this.name)} | ${(this as any).os.instanceName}`;
});
},
onLoaded() {

View File

@@ -48,7 +48,7 @@ export default Vue.extend({
this.user = user;
this.fetching = false;
document.title = '%i18n:@followers-of%'.replace('{}', this.name) + ' | ' + (this as any).os.instanceName;
document.title = `${'%i18n:@followers-of%'.replace('{}', this.name)} | ${(this as any).os.instanceName}`;
});
},
onLoaded() {

View File

@@ -16,10 +16,10 @@ export default Vue.extend({
methods: {
nav(game, actualNav) {
if (actualNav) {
this.$router.push('/reversi/' + game.id);
this.$router.push(`/reversi/${game.id}`);
} else {
// TODO: https://github.com/vuejs/vue-router/issues/703
this.$router.push('/reversi/' + game.id);
this.$router.push(`/reversi/${game.id}`);
}
}
}

View File

@@ -42,10 +42,6 @@
<mk-user-list-timeline v-if="src == 'list'" ref="tl" :key="list.id" :list="list"/>
</div>
</main>
<modal name="postForm">
<mk-post-form @posted="postFormClosed" @cancel="postFormClosed"/>
</modal>
</mk-ui>
</template>
@@ -111,11 +107,7 @@ export default Vue.extend({
methods: {
fn() {
this.$modal.push('postForm');
},
postFormClosed() {
this.$modal.pop();
(this as any).apis.post();
},
saveSrc() {

View File

@@ -2,7 +2,7 @@
<mk-ui>
<span slot="header">%fa:cog%%i18n:@settings%</span>
<main :data-darkmode="$store.state.device.darkmode">
<div class="signin-as" v-html="'%i18n:@signed-in-as%'.replace('{}', '<b>' + name + '</b>')"></div>
<div class="signin-as" v-html="'%i18n:@signed-in-as%'.replace('{}', `<b>${name}</b>`)"></div>
<div>
<x-profile/>
@@ -10,80 +10,101 @@
<ui-card>
<div slot="title">%fa:palette% %i18n:@design%</div>
<ui-switch v-model="darkmode">%i18n:@dark-mode%</ui-switch>
<ui-switch v-model="$store.state.settings.circleIcons" @change="onChangeCircleIcons">%i18n:@circle-icons%</ui-switch>
<ui-switch v-model="$store.state.settings.iLikeSushi" @change="onChangeILikeSushi">%i18n:common.i-like-sushi%</ui-switch>
<ui-switch v-model="$store.state.settings.disableAnimatedMfm" @change="onChangeDisableAnimatedMfm">%i18n:common.disable-animated-mfm%</ui-switch>
<ui-switch v-model="$store.state.settings.games.reversi.showBoardLabels" @change="onChangeReversiBoardLabels">%i18n:common.show-reversi-board-labels%</ui-switch>
<ui-switch v-model="$store.state.settings.games.reversi.useContrastStones" @change="onChangeUseContrastReversiStones">%i18n:common.use-contrast-reversi-stones%</ui-switch>
<section>
<ui-switch v-model="darkmode">%i18n:@dark-mode%</ui-switch>
<ui-switch v-model="$store.state.settings.circleIcons" @change="onChangeCircleIcons">%i18n:@circle-icons%</ui-switch>
<ui-switch v-model="$store.state.settings.iLikeSushi" @change="onChangeILikeSushi">%i18n:common.i-like-sushi%</ui-switch>
<ui-switch v-model="$store.state.settings.disableAnimatedMfm" @change="onChangeDisableAnimatedMfm">%i18n:common.disable-animated-mfm%</ui-switch>
<ui-switch v-model="$store.state.settings.games.reversi.showBoardLabels" @change="onChangeReversiBoardLabels">%i18n:common.show-reversi-board-labels%</ui-switch>
<ui-switch v-model="$store.state.settings.games.reversi.useContrastStones" @change="onChangeUseContrastReversiStones">%i18n:common.use-contrast-reversi-stones%</ui-switch>
</section>
<div>
<div>%i18n:@timeline%</div>
<ui-switch v-model="$store.state.settings.showReplyTarget" @change="onChangeShowReplyTarget">%i18n:@show-reply-target%</ui-switch>
<ui-switch v-model="$store.state.settings.showMyRenotes" @change="onChangeShowMyRenotes">%i18n:@show-my-renotes%</ui-switch>
<ui-switch v-model="$store.state.settings.showRenotedMyNotes" @change="onChangeShowRenotedMyNotes">%i18n:@show-renoted-my-notes%</ui-switch>
<ui-switch v-model="$store.state.settings.showLocalRenotes" @change="onChangeShowLocalRenotes">%i18n:@show-local-renotes%</ui-switch>
</div>
<section>
<header>%i18n:@timeline%</header>
<div>
<ui-switch v-model="$store.state.settings.showReplyTarget" @change="onChangeShowReplyTarget">%i18n:@show-reply-target%</ui-switch>
<ui-switch v-model="$store.state.settings.showMyRenotes" @change="onChangeShowMyRenotes">%i18n:@show-my-renotes%</ui-switch>
<ui-switch v-model="$store.state.settings.showRenotedMyNotes" @change="onChangeShowRenotedMyNotes">%i18n:@show-renoted-my-notes%</ui-switch>
<ui-switch v-model="$store.state.settings.showLocalRenotes" @change="onChangeShowLocalRenotes">%i18n:@show-local-renotes%</ui-switch>
</div>
</section>
<div>
<div>%i18n:@post-style%</div>
<section>
<header>%i18n:@post-style%</header>
<ui-radio v-model="postStyle" value="standard">%i18n:@post-style-standard%</ui-radio>
<ui-radio v-model="postStyle" value="smart">%i18n:@post-style-smart%</ui-radio>
</div>
</section>
<section>
<header>%i18n:@notification-position%</header>
<ui-radio v-model="mobileNotificationPosition" value="bottom">%i18n:@notification-position-bottom%</ui-radio>
<ui-radio v-model="mobileNotificationPosition" value="top">%i18n:@notification-position-top%</ui-radio>
</section>
</ui-card>
<ui-card>
<div slot="title">%fa:cog% %i18n:@behavior%</div>
<ui-switch v-model="$store.state.settings.fetchOnScroll" @change="onChangeFetchOnScroll">%i18n:@fetch-on-scroll%</ui-switch>
<ui-switch v-model="$store.state.settings.disableViaMobile" @change="onChangeDisableViaMobile">%i18n:@disable-via-mobile%</ui-switch>
<ui-switch v-model="loadRawImages">%i18n:@load-raw-images%</ui-switch>
<ui-switch v-model="$store.state.settings.loadRemoteMedia" @change="onChangeLoadRemoteMedia">%i18n:@load-remote-media%</ui-switch>
<ui-switch v-model="lightmode">%i18n:@i-am-under-limited-internet%</ui-switch>
<section>
<ui-switch v-model="$store.state.settings.fetchOnScroll" @change="onChangeFetchOnScroll">%i18n:@fetch-on-scroll%</ui-switch>
<ui-switch v-model="$store.state.settings.disableViaMobile" @change="onChangeDisableViaMobile">%i18n:@disable-via-mobile%</ui-switch>
<ui-switch v-model="loadRawImages">%i18n:@load-raw-images%</ui-switch>
<ui-switch v-model="$store.state.settings.loadRemoteMedia" @change="onChangeLoadRemoteMedia">%i18n:@load-remote-media%</ui-switch>
<ui-switch v-model="lightmode">%i18n:@i-am-under-limited-internet%</ui-switch>
</section>
</ui-card>
<ui-card>
<div slot="title">%fa:volume-up% %i18n:@sound%</div>
<ui-switch v-model="enableSounds">%i18n:@enable-sounds%</ui-switch>
<section>
<ui-switch v-model="enableSounds">%i18n:@enable-sounds%</ui-switch>
</section>
</ui-card>
<ui-card>
<div slot="title">%fa:language% %i18n:@lang%</div>
<ui-select v-model="lang" placeholder="%i18n:@auto%">
<optgroup label="%i18n:@recommended%">
<option value="">%i18n:@auto%</option>
</optgroup>
<section class="fit-top">
<ui-select v-model="lang" placeholder="%i18n:@auto%">
<optgroup label="%i18n:@recommended%">
<option value="">%i18n:@auto%</option>
</optgroup>
<optgroup label="%i18n:@specify-language%">
<option v-for="x in langs" :value="x[0]" :key="x[0]">{{ x[1] }}</option>
</optgroup>
</ui-select>
<span>%fa:info-circle% %i18n:@lang-tip%</span>
<optgroup label="%i18n:@specify-language%">
<option v-for="x in langs" :value="x[0]" :key="x[0]">{{ x[1] }}</option>
</optgroup>
</ui-select>
<span>%fa:info-circle% %i18n:@lang-tip%</span>
</section>
</ui-card>
<ui-card>
<div slot="title">%fa:B twitter% %i18n:@twitter%</div>
<p class="account" v-if="$store.state.i.twitter"><a :href="`https://twitter.com/${$store.state.i.twitter.screenName}`" target="_blank">@{{ $store.state.i.twitter.screenName }}</a></p>
<p>
<a :href="`${apiUrl}/connect/twitter`" target="_blank">{{ $store.state.i.twitter ? '%i18n:@twitter-reconnect%' : '%i18n:@twitter-connect%' }}</a>
<span v-if="$store.state.i.twitter"> or </span>
<a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="$store.state.i.twitter">%i18n:@twitter-disconnect%</a>
</p>
<section>
<p class="account" v-if="$store.state.i.twitter"><a :href="`https://twitter.com/${$store.state.i.twitter.screenName}`" target="_blank">@{{ $store.state.i.twitter.screenName }}</a></p>
<p>
<a :href="`${apiUrl}/connect/twitter`" target="_blank">{{ $store.state.i.twitter ? '%i18n:@twitter-reconnect%' : '%i18n:@twitter-connect%' }}</a>
<span v-if="$store.state.i.twitter"> or </span>
<a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="$store.state.i.twitter">%i18n:@twitter-disconnect%</a>
</p>
</section>
</ui-card>
<ui-card>
<div slot="title">%fa:sync-alt% %i18n:@update%</div>
<div>%i18n:@version% <i>{{ version }}</i></div>
<template v-if="latestVersion !== undefined">
<div>%i18n:@latest-version% <i>{{ latestVersion ? latestVersion : version }}</i></div>
</template>
<ui-button @click="checkForUpdate" :disabled="checkingForUpdate">
<template v-if="checkingForUpdate">%i18n:@update-checking%<mk-ellipsis/></template>
<template v-else>%i18n:@check-for-updates%</template>
</ui-button>
<section>
<div>%i18n:@version% <i>{{ version }}</i></div>
<template v-if="latestVersion !== undefined">
<div>%i18n:@latest-version% <i>{{ latestVersion ? latestVersion : version }}</i></div>
</template>
<ui-button @click="checkForUpdate" :disabled="checkingForUpdate">
<template v-if="checkingForUpdate">%i18n:@update-checking%<mk-ellipsis/></template>
<template v-else>%i18n:@check-for-updates%</template>
</ui-button>
</section>
</ui-card>
</div>
@@ -134,6 +155,11 @@ export default Vue.extend({
set(value) { this.$store.commit('device/set', { key: 'postStyle', value }); }
},
mobileNotificationPosition: {
get() { return this.$store.state.device.mobileNotificationPosition; },
set(value) { this.$store.commit('device/set', { key: 'mobileNotificationPosition', value }); }
},
lightmode: {
get() { return this.$store.state.device.lightmode; },
set(value) { this.$store.commit('device/set', { key: 'lightmode', value }); }
@@ -273,7 +299,7 @@ export default Vue.extend({
<style lang="stylus" scoped>
root(isDark)
margin 0 auto
max-width 500px
max-width 600px
width 100%
> .signin-as

View File

@@ -2,47 +2,49 @@
<ui-card>
<div slot="title">%fa:user% %i18n:@title%</div>
<ui-form :disabled="saving">
<ui-input v-model="name" :max="30">
<span>%i18n:@name%</span>
</ui-input>
<section class="fit-top">
<ui-form :disabled="saving">
<ui-input v-model="name" :max="30">
<span>%i18n:@name%</span>
</ui-input>
<ui-input v-model="username" readonly>
<span>%i18n:@account%</span>
<span slot="prefix">@</span>
<span slot="suffix">@{{ host }}</span>
</ui-input>
<ui-input v-model="username" readonly>
<span>%i18n:@account%</span>
<span slot="prefix">@</span>
<span slot="suffix">@{{ host }}</span>
</ui-input>
<ui-input v-model="location">
<span>%i18n:@location%</span>
<span slot="prefix">%fa:map-marker-alt%</span>
</ui-input>
<ui-input v-model="location">
<span>%i18n:@location%</span>
<span slot="prefix">%fa:map-marker-alt%</span>
</ui-input>
<ui-input v-model="birthday" type="date">
<span>%i18n:@birthday%</span>
<span slot="prefix">%fa:birthday-cake%</span>
</ui-input>
<ui-input v-model="birthday" type="date">
<span>%i18n:@birthday%</span>
<span slot="prefix">%fa:birthday-cake%</span>
</ui-input>
<ui-textarea v-model="description" :max="500">
<span>%i18n:@description%</span>
</ui-textarea>
<ui-textarea v-model="description" :max="500">
<span>%i18n:@description%</span>
</ui-textarea>
<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>
</ui-input>
<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>
</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>
</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>
</ui-input>
<ui-switch v-model="isCat">%i18n:@is-cat%</ui-switch>
<ui-switch v-model="isCat">%i18n:@is-cat%</ui-switch>
<ui-button @click="save">%i18n:@save%</ui-button>
</ui-form>
<ui-button @click="save">%i18n:@save%</ui-button>
</ui-form>
</section>
</ui-card>
</template>

View File

@@ -43,7 +43,7 @@ export default Vue.extend({
title
});
this.$router.push('/i/lists/' + list.id);
this.$router.push(`/i/lists/${list.id}`);
});
}
}

View File

@@ -107,7 +107,7 @@ export default Vue.extend({
this.fetching = false;
Progress.done();
document.title = Vue.filter('userName')(this.user) + ' | ' + (this as any).os.instanceName;
document.title = `${Vue.filter('userName')(this.user)} | ${(this as any).os.instanceName}`;
});
}
}

View File

@@ -43,7 +43,8 @@ const defaultDeviceSettings = {
debug: false,
lightmode: false,
loadRawImages: false,
postStyle: 'standard'
postStyle: 'standard',
mobileNotificationPosition: 'bottom'
};
export default (os: MiOS) => new Vuex.Store({

View File

@@ -7,6 +7,7 @@ import { URL } from 'url';
import * as yaml from 'js-yaml';
import { Source, Mixin } from './types';
import isUrl = require('is-url');
const pkg = require('../../package.json');
/**
* Path of configuration directory
@@ -43,6 +44,7 @@ export default function load() {
mixin.stats_url = `${mixin.scheme}://${mixin.host}/stats`;
mixin.status_url = `${mixin.scheme}://${mixin.host}/status`;
mixin.drive_url = `${mixin.scheme}://${mixin.host}/files`;
mixin.user_agent = `Misskey/${pkg.version} (${config.url})`;
if (config.localDriveCapacityMb == null) config.localDriveCapacityMb = 256;
if (config.remoteDriveCapacityMb == null) config.remoteDriveCapacityMb = 8;

View File

@@ -114,6 +114,7 @@ export type Mixin = {
status_url: string;
dev_url: string;
drive_url: string;
user_agent: string;
};
export type Config = Source & Mixin;

View File

@@ -16,7 +16,7 @@ export default function() {
});
ev.on('requestNotesStatsLog', id => {
ev.emit('notesStatsLog:' + id, log.toArray());
ev.emit(`notesStatsLog:${id}`, log.toArray());
});
process.on('exit', code => {

View File

@@ -16,7 +16,7 @@ export default function() {
const log = new Deque<any>();
ev.on('requestServerStatsLog', x => {
ev.emit('serverStatsLog:' + x.id, log.toArray().slice(0, x.length || 50));
ev.emit(`serverStatsLog:${x.id}`, log.toArray().slice(0, x.length || 50));
});
async function tick() {

View File

@@ -205,13 +205,7 @@ export default class Reversi {
* 打つことができる場所を取得します
*/
public canPutSomewhere(color: Color): number[] {
const result: number[] = [];
this.board.forEach((x, i) => {
if (this.canPut(color, i)) result.push(i);
});
return result;
return Array.from(this.board.keys()).filter(i => this.canPut(color, i));
}
/**

View File

@@ -20,7 +20,6 @@ import Logger from './misc/logger';
import ProgressBar from './misc/cli/progressbar';
import EnvironmentInfo from './misc/environmentInfo';
import MachineInfo from './misc/machineInfo';
import DependencyInfo from './misc/dependencyInfo';
import serverStats from './daemons/server-stats';
import notesStats from './daemons/notes-stats';
import loadConfig from './config/load';
@@ -116,7 +115,6 @@ async function init(): Promise<Config> {
new Logger('Deps').info(`Node.js ${process.version}`);
MachineInfo.show();
EnvironmentInfo.show();
new DependencyInfo().showAll();
const configLogger = new Logger('Config');
let config;

View File

@@ -33,26 +33,27 @@ export default function(html: string): string {
case 'a':
const txt = getText(node);
const rel = node.attrs.find((x: any) => x.name == 'rel');
const href = node.attrs.find((x: any) => x.name == 'href');
// ハッシュタグ / hrefがない / txtがURL
if ((rel && rel.value.match('tag') !== null) || !href || href.value == txt) {
text += txt;
// メンション
if (txt.startsWith('@')) {
} else if (txt.startsWith('@')) {
const part = txt.split('@');
if (part.length == 2) {
//#region ホスト名部分が省略されているので復元する
const href = new URL(node.attrs.find((x: any) => x.name == 'href').value);
const acct = txt + '@' + href.hostname;
const acct = `${txt}@${(new URL(href.value)).hostname}`;
text += acct;
break;
//#endregion
} else if (part.length == 3) {
text += txt;
break;
}
}
if (node.childNodes) {
node.childNodes.forEach((n: any) => analyze(n));
// その他
} else {
text += `[${txt}](${href.value})`;
}
break;

View File

@@ -44,8 +44,8 @@ const handlers: { [key: string]: (window: any, token: any, mentionedRemoteUsers:
hashtag({ document }, { hashtag }) {
const a = document.createElement('a');
a.href = config.url + '/tags/' + hashtag;
a.textContent = '#' + hashtag;
a.href = `${config.url}/tags/${hashtag}`;
a.textContent = `#${hashtag}`;
a.setAttribute('rel', 'tag');
document.body.appendChild(a);
},

View File

@@ -1,32 +0,0 @@
import Logger from './logger';
import { execSync } from 'child_process';
export default class {
private logger: Logger;
constructor() {
this.logger = new Logger('Deps');
}
public showAll(): void {
this.show('MongoDB', 'mongo --version', x => x.match(/^MongoDB shell version:? v(.*)\r?\n/));
this.show('Redis', 'redis-server --version', x => x.match(/v=([0-9\.]*)/));
}
public show(serviceName: string, command: string, transform: (x: string) => RegExpMatchArray): void {
try {
// ステータス0以外のときにexecSyncはstderrをコンソール上に出力してしまうので
// プロセスからのstderrをすべて無視するように stdio オプションをセット
const x = execSync(command, { stdio: ['pipe', 'pipe', 'ignore'] });
const ver = transform(x.toString());
if (ver != null) {
this.logger.succ(`${serviceName} ${ver[1]} found`);
} else {
this.logger.warn(`${serviceName} not found`);
this.logger.warn(`Regexp used for version check of ${serviceName} is probably messed up`);
}
} catch (e) {
this.logger.warn(`${serviceName} not found`);
}
}
}

View File

@@ -26,7 +26,7 @@ export const replacement = (match: string, key: string) => {
arg == 'B' ? 'fab' :
'';
} else if (arg.startsWith('.')) {
classes.push('fa-' + arg.substr(1));
classes.push(`fa-${arg.substr(1)}`);
} else if (arg.startsWith('-')) {
transform = arg.substr(1).split('|').join(' ');
} else {

View File

@@ -193,5 +193,10 @@ export const pack = (
*/
}
delete _target.withoutChunks;
delete _target.storage;
delete _target.storageProps;
delete _target.isRemote;
resolve(_target);
});

View File

@@ -2,7 +2,12 @@ import * as mongo from 'mongodb';
import db from '../db/mongodb';
const Stats = db.get<IStats>('stats');
Stats.dropIndex({ date: -1 }); // 後方互換性のため
// 後方互換性のため
Stats.dropIndex({ date: -1 } as any).catch((e: mongo.MongoError) => {
if (e.code !== 27) throw e;
});
Stats.createIndex({ span: -1, date: -1 }, { unique: true });
export default Stats;

View File

@@ -432,10 +432,10 @@ export const pack = (
followerId: _user.id,
followeeId: meId
}),
_user.isLocked ? FollowRequest.findOne({
FollowRequest.findOne({
followerId: meId,
followeeId: _user.id
}) : Promise.resolve(null),
}),
FollowRequest.findOne({
followerId: _user.id,
followeeId: meId

View File

@@ -5,7 +5,7 @@ const httpSignature = require('http-signature');
import parseAcct from '../../../misc/acct/parse';
import User, { IRemoteUser } from '../../../models/user';
import perform from '../../../remote/activitypub/perform';
import { resolvePerson } from '../../../remote/activitypub/models/person';
import { resolvePerson, updatePerson } from '../../../remote/activitypub/models/person';
import { toUnicode } from 'punycode';
import { URL } from 'url';
@@ -44,11 +44,6 @@ export default async (job: bq.Job, done: any): Promise<void> => {
}
user = await User.findOne({ usernameLower: username, host: host.toLowerCase() }) as IRemoteUser;
// アクティビティを送信してきたユーザーがまだMisskeyサーバーに登録されていなかったら登録する
if (user === null) {
user = await resolvePerson(activity.actor) as IRemoteUser;
}
} else {
// アクティビティ内のホストの検証
const host = toUnicode(new URL(signature.keyId).hostname.toLowerCase());
@@ -64,11 +59,26 @@ export default async (job: bq.Job, done: any): Promise<void> => {
host: { $ne: null },
'publicKey.id': signature.keyId
}) as IRemoteUser;
}
// アクティビティを送信してきたユーザーがまだMisskeyサーバーに登録されていなかったら登録する
if (user === null) {
user = await resolvePerson(activity.actor) as IRemoteUser;
// Update activityの場合は、ここで署名検証/更新処理まで実施して終了
if (activity.type === 'Update') {
if (activity.object && activity.object.type === 'Person') {
if (user == null) {
console.warn('Update activity received, but user not registed.');
} else if (!httpSignature.verifySignature(signature, user.publicKey.publicKeyPem)) {
console.warn('Update activity received, but signature verification failed.');
} else {
updatePerson(activity.actor, null, activity.object);
}
}
done();
return;
}
// アクティビティを送信してきたユーザーがまだMisskeyサーバーに登録されていなかったら登録する
if (user === null) {
user = await resolvePerson(activity.actor) as IRemoteUser;
}
if (user === null) {

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