Compare commits
	
		
			272 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					d44dc7e00d | ||
| 
						 | 
					82ee3a538b | ||
| 
						 | 
					380cf0de69 | ||
| 
						 | 
					11f25ea2e7 | ||
| 
						 | 
					ef62497777 | ||
| 
						 | 
					2824d8a5b6 | ||
| 
						 | 
					1c84c0828e | ||
| 
						 | 
					39e4494836 | ||
| 
						 | 
					e7180d529a | ||
| 
						 | 
					b8cd872738 | ||
| 
						 | 
					efaaa76185 | ||
| 
						 | 
					19e1f996a6 | ||
| 
						 | 
					40a69bf200 | ||
| 
						 | 
					9e3abb9989 | ||
| 
						 | 
					5ba48e06f7 | ||
| 
						 | 
					8b3a0a524b | ||
| 
						 | 
					d9fe9cc5df | ||
| 
						 | 
					b202c7906a | ||
| 
						 | 
					b9c868cac6 | ||
| 
						 | 
					33adf3c88d | ||
| 
						 | 
					8b84f40975 | ||
| 
						 | 
					fa131d2023 | ||
| 
						 | 
					a83b38b50a | ||
| 
						 | 
					dcd7b286ef | ||
| 
						 | 
					b85bf769cd | ||
| 
						 | 
					630a20d61e | ||
| 
						 | 
					88c3794cf1 | ||
| 
						 | 
					42eb457ad0 | ||
| 
						 | 
					d153a8de20 | ||
| 
						 | 
					7f7551f44c | ||
| 
						 | 
					23082b55a4 | ||
| 
						 | 
					dac7387a7f | ||
| 
						 | 
					8c6856d894 | ||
| 
						 | 
					2c0e514fb2 | ||
| 
						 | 
					1917b0339e | ||
| 
						 | 
					c05419f223 | ||
| 
						 | 
					e0deaec695 | ||
| 
						 | 
					d70e2a788e | ||
| 
						 | 
					7343e6e2e8 | ||
| 
						 | 
					106d4cc0d6 | ||
| 
						 | 
					c98879cb7a | ||
| 
						 | 
					9ca755c313 | ||
| 
						 | 
					25e0b98840 | ||
| 
						 | 
					5599c43c71 | ||
| 
						 | 
					eb7597d7e4 | ||
| 
						 | 
					d5767e92c4 | ||
| 
						 | 
					ba3749d373 | ||
| 
						 | 
					d8088acdf2 | ||
| 
						 | 
					ad93e0aa3d | ||
| 
						 | 
					691e58f03d | ||
| 
						 | 
					95d5bccfca | ||
| 
						 | 
					2aa8e0a4bf | ||
| 
						 | 
					6e96d6677d | ||
| 
						 | 
					8816c20f51 | ||
| 
						 | 
					e955fe1ffd | ||
| 
						 | 
					5cbcac713a | ||
| 
						 | 
					2b50364ab4 | ||
| 
						 | 
					fa04ac789e | ||
| 
						 | 
					95ce8dce3d | ||
| 
						 | 
					0b5eec4ca8 | ||
| 
						 | 
					6d9716f90e | ||
| 
						 | 
					aa31061d90 | ||
| 
						 | 
					acc7797dff | ||
| 
						 | 
					7959196dc7 | ||
| 
						 | 
					c6ff6939a5 | ||
| 
						 | 
					769960f29e | ||
| 
						 | 
					d92e9759f3 | ||
| 
						 | 
					bf7e19b288 | ||
| 
						 | 
					98954cd6d4 | ||
| 
						 | 
					538bb978ed | ||
| 
						 | 
					10232c5866 | ||
| 
						 | 
					5cd6a0db16 | ||
| 
						 | 
					ff0a05a2d6 | ||
| 
						 | 
					e34b264af2 | ||
| 
						 | 
					00d79487cd | ||
| 
						 | 
					3cace734c7 | ||
| 
						 | 
					f428372869 | ||
| 
						 | 
					5dd2feba9b | ||
| 
						 | 
					a1b026239e | ||
| 
						 | 
					40735ce76b | ||
| 
						 | 
					4a00c13b33 | ||
| 
						 | 
					8e359d54bd | ||
| 
						 | 
					fb76dff836 | ||
| 
						 | 
					2448bf4e4e | ||
| 
						 | 
					91e0fc8c62 | ||
| 
						 | 
					b4f86feddb | ||
| 
						 | 
					7167c8c593 | ||
| 
						 | 
					51b79d4250 | ||
| 
						 | 
					925fcc1c64 | ||
| 
						 | 
					fcdc14862c | ||
| 
						 | 
					dac2844cae | ||
| 
						 | 
					706b0cea16 | ||
| 
						 | 
					842e7844c7 | ||
| 
						 | 
					1dceda50d8 | ||
| 
						 | 
					af8b9abba4 | ||
| 
						 | 
					07b07685fa | ||
| 
						 | 
					cde43fe3c8 | ||
| 
						 | 
					2fe84aa75b | ||
| 
						 | 
					7d79a4840d | ||
| 
						 | 
					3ee9479572 | ||
| 
						 | 
					ccf8e44acc | ||
| 
						 | 
					451acb77df | ||
| 
						 | 
					e2c6227f47 | ||
| 
						 | 
					ebd1c877ad | ||
| 
						 | 
					498094b3c7 | ||
| 
						 | 
					1cc183ecdb | ||
| 
						 | 
					e8948452fd | ||
| 
						 | 
					ade7e62836 | ||
| 
						 | 
					395cfa6108 | ||
| 
						 | 
					b5ff2abdb9 | ||
| 
						 | 
					229e85b2c5 | ||
| 
						 | 
					37058e3480 | ||
| 
						 | 
					a1b82e9723 | ||
| 
						 | 
					db943df0c8 | ||
| 
						 | 
					ff8d300ea8 | ||
| 
						 | 
					8b490b9b94 | ||
| 
						 | 
					f83f8631ac | ||
| 
						 | 
					16da91d8d1 | ||
| 
						 | 
					8ffd62b462 | ||
| 
						 | 
					935367e167 | ||
| 
						 | 
					00618260f2 | ||
| 
						 | 
					77d66fac7b | ||
| 
						 | 
					17d7f59b06 | ||
| 
						 | 
					2561547db1 | ||
| 
						 | 
					7738438616 | ||
| 
						 | 
					3d8fc4a794 | ||
| 
						 | 
					87b4e7905e | ||
| 
						 | 
					13c5d4985a | ||
| 
						 | 
					f0df4096fd | ||
| 
						 | 
					5044424549 | ||
| 
						 | 
					8ce67cdcd6 | ||
| 
						 | 
					1915ccabdd | ||
| 
						 | 
					6fea2f52f1 | ||
| 
						 | 
					f77eaaa08a | ||
| 
						 | 
					7c5bc03492 | ||
| 
						 | 
					72a1af6cd4 | ||
| 
						 | 
					4bce6f14f3 | ||
| 
						 | 
					a38ce86f87 | ||
| 
						 | 
					f539491502 | ||
| 
						 | 
					d279f8e9ff | ||
| 
						 | 
					eaec936fa6 | ||
| 
						 | 
					a0735b0e7a | ||
| 
						 | 
					5b039a1bee | ||
| 
						 | 
					921609cab1 | ||
| 
						 | 
					199573ccee | ||
| 
						 | 
					977200b7cd | ||
| 
						 | 
					6abff253ea | ||
| 
						 | 
					ba64de334a | ||
| 
						 | 
					dc1d7fa9d7 | ||
| 
						 | 
					f42665d4bc | ||
| 
						 | 
					a5eb19c878 | ||
| 
						 | 
					60fa8e13d6 | ||
| 
						 | 
					ecbaea463b | ||
| 
						 | 
					814ddeb436 | ||
| 
						 | 
					d6466106e8 | ||
| 
						 | 
					633f5384f9 | ||
| 
						 | 
					fa7989772c | ||
| 
						 | 
					0e395612a6 | ||
| 
						 | 
					fb3f52f3ad | ||
| 
						 | 
					ba11c71d65 | ||
| 
						 | 
					bdc3081167 | ||
| 
						 | 
					430efcf1b9 | ||
| 
						 | 
					996450dd7c | ||
| 
						 | 
					fa779f0417 | ||
| 
						 | 
					25cec6d28a | ||
| 
						 | 
					c5f8403cea | ||
| 
						 | 
					a9ae9a65c8 | ||
| 
						 | 
					3698c679e2 | ||
| 
						 | 
					881df20f1b | ||
| 
						 | 
					7d269c0441 | ||
| 
						 | 
					ba38f64353 | ||
| 
						 | 
					db3ae303cb | ||
| 
						 | 
					66f3a155e6 | ||
| 
						 | 
					639b483e6c | ||
| 
						 | 
					09843a409b | ||
| 
						 | 
					e894ed5a8b | ||
| 
						 | 
					d7808299fd | ||
| 
						 | 
					f92e0c16d2 | ||
| 
						 | 
					d94b3757be | ||
| 
						 | 
					13e822cba6 | ||
| 
						 | 
					c57bf87f52 | ||
| 
						 | 
					99fbd60265 | ||
| 
						 | 
					ea9b48db3c | ||
| 
						 | 
					c145c994a9 | ||
| 
						 | 
					d033998b56 | ||
| 
						 | 
					3136c714bf | ||
| 
						 | 
					c0ee134f19 | ||
| 
						 | 
					d15ebe5732 | ||
| 
						 | 
					ef630195fa | ||
| 
						 | 
					e31921151e | ||
| 
						 | 
					f94992abbe | ||
| 
						 | 
					b00060c09c | ||
| 
						 | 
					f6217d96d2 | ||
| 
						 | 
					3a6947c7ed | ||
| 
						 | 
					0fb528ddf8 | ||
| 
						 | 
					14c03f226d | ||
| 
						 | 
					4f0d844b43 | ||
| 
						 | 
					b93395fc4c | ||
| 
						 | 
					34eacb7e2d | ||
| 
						 | 
					0177023ead | ||
| 
						 | 
					a4678e45de | ||
| 
						 | 
					f24869625e | ||
| 
						 | 
					01beb705a2 | ||
| 
						 | 
					ce28c70c35 | ||
| 
						 | 
					5e0f5c31e7 | ||
| 
						 | 
					b28dd4be52 | ||
| 
						 | 
					291beb45fc | ||
| 
						 | 
					ffb345ccb5 | ||
| 
						 | 
					d2abe2cd81 | ||
| 
						 | 
					acffc3e522 | ||
| 
						 | 
					0962e62b8c | ||
| 
						 | 
					91ebd310b7 | ||
| 
						 | 
					2974c74b4e | ||
| 
						 | 
					3d24112d2d | ||
| 
						 | 
					4a977cd523 | ||
| 
						 | 
					4b1886990f | ||
| 
						 | 
					f3499b787c | ||
| 
						 | 
					5209a584a2 | ||
| 
						 | 
					57a63d38aa | ||
| 
						 | 
					3efffbcf22 | ||
| 
						 | 
					15eaebe522 | ||
| 
						 | 
					eee98358ac | ||
| 
						 | 
					795fc5e7bc | ||
| 
						 | 
					70ac668474 | ||
| 
						 | 
					1004e0d6e8 | ||
| 
						 | 
					52aa64fcb6 | ||
| 
						 | 
					7860d97a10 | ||
| 
						 | 
					409b37b271 | ||
| 
						 | 
					ad9b9964fa | ||
| 
						 | 
					d2b5276f43 | ||
| 
						 | 
					7204e2a84c | ||
| 
						 | 
					1377fa3332 | ||
| 
						 | 
					bf087bfccf | ||
| 
						 | 
					e846e3d571 | ||
| 
						 | 
					d646e62888 | ||
| 
						 | 
					c008154d18 | ||
| 
						 | 
					29bd4de26a | ||
| 
						 | 
					7559b8da6c | ||
| 
						 | 
					35218e84fc | ||
| 
						 | 
					2c135fa2f6 | ||
| 
						 | 
					21da6bd047 | ||
| 
						 | 
					f1d65a66b4 | ||
| 
						 | 
					63e2dbbb0d | ||
| 
						 | 
					a228c522f1 | ||
| 
						 | 
					a951c337b8 | ||
| 
						 | 
					db3efb3791 | ||
| 
						 | 
					5f9a9867eb | ||
| 
						 | 
					059a8e07d2 | ||
| 
						 | 
					cf82f56e66 | ||
| 
						 | 
					2778bd14d4 | ||
| 
						 | 
					5b0446739c | ||
| 
						 | 
					55f235d0ac | ||
| 
						 | 
					4ec44c68e9 | ||
| 
						 | 
					e6952d499a | ||
| 
						 | 
					e0b82f827b | ||
| 
						 | 
					0bccb17e82 | ||
| 
						 | 
					b251b8c6a9 | ||
| 
						 | 
					c2a62f632b | ||
| 
						 | 
					37b5afa1a3 | ||
| 
						 | 
					b80d0a3b12 | ||
| 
						 | 
					9f60688d37 | ||
| 
						 | 
					ca0ea9e57c | ||
| 
						 | 
					a77a7e8112 | ||
| 
						 | 
					b26ea2edc0 | ||
| 
						 | 
					02b99dfd76 | ||
| 
						 | 
					af02b0f115 | ||
| 
						 | 
					9b3c379678 | ||
| 
						 | 
					a423fd7695 | ||
| 
						 | 
					de6e1d8c9b | ||
| 
						 | 
					d9db3e8629 | ||
| 
						 | 
					ac1c81b7d6 | ||
| 
						 | 
					49b2eec534 | 
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
-----
 | 
			
		||||
 
 | 
			
		||||
@@ -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 ディレクトリに存在します。
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
## テストの追加
 | 
			
		||||
現在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`.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										29
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								README.md
									
									
									
									
									
								
							@@ -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.
 | 
			
		||||
 | 
			
		||||
[](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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								assets/about/drive.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/about/drive.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 110 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								assets/about/post.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/about/post.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 344 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								assets/about/reaction.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/about/reaction.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 24 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								assets/about/ui.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/about/ui.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 125 KiB  | 
@@ -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
 | 
			
		||||
 | 
			
		||||
----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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)でマイグレーション情報を確認する
 | 
			
		||||
 | 
			
		||||
----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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.
 | 
			
		||||
 
 | 
			
		||||
@@ -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: "表示を切り替え"
 | 
			
		||||
@@ -647,6 +651,7 @@ desktop/views/components/settings.vue:
 | 
			
		||||
  delete-wallpaper: "壁紙を削除"
 | 
			
		||||
  dark-mode: "ダークモード"
 | 
			
		||||
  circle-icons: "円形のアイコンを使用"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用"
 | 
			
		||||
  post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
 | 
			
		||||
  suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
 | 
			
		||||
@@ -861,7 +866,10 @@ desktop/views/pages/welcome.vue:
 | 
			
		||||
  signin-button: "やってる"
 | 
			
		||||
  signup-button: "やる"
 | 
			
		||||
  timeline: "タイムライン"
 | 
			
		||||
  announcements: "お知らせ"
 | 
			
		||||
  photos: "最近の画像"
 | 
			
		||||
  powered-by-misskey: "Powered by <b>Misskey</b>."
 | 
			
		||||
  info: "情報"
 | 
			
		||||
desktop/views/pages/drive.vue:
 | 
			
		||||
  title: "Misskey Drive"
 | 
			
		||||
desktop/views/pages/favorites.vue:
 | 
			
		||||
@@ -1149,6 +1157,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  dark-mode: "ダークモード"
 | 
			
		||||
  i-am-under-limited-internet: "私は通信を制限されている"
 | 
			
		||||
  circle-icons: "円形のアイコンを使用"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  timeline: "タイムライン"
 | 
			
		||||
  show-reply-target: "リプライ先を表示する"
 | 
			
		||||
  show-my-renotes: "自分の行ったRenoteを表示する"
 | 
			
		||||
@@ -1157,6 +1166,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: "「モバイルからの投稿」フラグを付けない"
 | 
			
		||||
@@ -1178,7 +1190,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  settings: "設定"
 | 
			
		||||
  signout: "サインアウト"
 | 
			
		||||
  sound: "サウンド"
 | 
			
		||||
  enableSounds: "サウンドを有効にする"
 | 
			
		||||
  enable-sounds: "サウンドを有効にする"
 | 
			
		||||
mobile/views/pages/user.vue:
 | 
			
		||||
  follows-you: "フォローされています"
 | 
			
		||||
  following: "フォロー"
 | 
			
		||||
 
 | 
			
		||||
@@ -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"
 | 
			
		||||
@@ -647,6 +651,7 @@ desktop/views/components/settings.vue:
 | 
			
		||||
  delete-wallpaper: "壁紙を削除"
 | 
			
		||||
  dark-mode: "Nacht Modus"
 | 
			
		||||
  circle-icons: "Kreisförmige Icons"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  gradient-window-header: "Übergang in Fensterköpfen"
 | 
			
		||||
  post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
 | 
			
		||||
  suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
 | 
			
		||||
@@ -861,7 +866,10 @@ desktop/views/pages/welcome.vue:
 | 
			
		||||
  signin-button: "やってる"
 | 
			
		||||
  signup-button: "やる"
 | 
			
		||||
  timeline: "タイムライン"
 | 
			
		||||
  announcements: "お知らせ"
 | 
			
		||||
  photos: "最近の画像"
 | 
			
		||||
  powered-by-misskey: "Powered by <b>Misskey</b>."
 | 
			
		||||
  info: "情報"
 | 
			
		||||
desktop/views/pages/drive.vue:
 | 
			
		||||
  title: "Misskey Drive"
 | 
			
		||||
desktop/views/pages/favorites.vue:
 | 
			
		||||
@@ -1149,6 +1157,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  dark-mode: "ダークモード"
 | 
			
		||||
  i-am-under-limited-internet: "私は通信を制限されている"
 | 
			
		||||
  circle-icons: "円形のアイコンを使用"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  timeline: "タイムライン"
 | 
			
		||||
  show-reply-target: "リプライ先を表示する"
 | 
			
		||||
  show-my-renotes: "自分の行ったRenoteを表示する"
 | 
			
		||||
@@ -1157,6 +1166,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: "「モバイルからの投稿」フラグを付けない"
 | 
			
		||||
@@ -1178,7 +1190,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  settings: "設定"
 | 
			
		||||
  signout: "サインアウト"
 | 
			
		||||
  sound: "サウンド"
 | 
			
		||||
  enableSounds: "サウンドを有効にする"
 | 
			
		||||
  enable-sounds: "サウンドを有効にする"
 | 
			
		||||
mobile/views/pages/user.vue:
 | 
			
		||||
  follows-you: "フォローされています"
 | 
			
		||||
  following: "フォロー"
 | 
			
		||||
 
 | 
			
		||||
@@ -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"
 | 
			
		||||
@@ -647,6 +651,7 @@ desktop/views/components/settings.vue:
 | 
			
		||||
  delete-wallpaper: "Remove background"
 | 
			
		||||
  dark-mode: "Dark Mode"
 | 
			
		||||
  circle-icons: "Use circle icons"
 | 
			
		||||
  contrasted-acct: "Add contrast to username"
 | 
			
		||||
  gradient-window-header: "Use gradients on window headers"
 | 
			
		||||
  post-form-on-timeline: "Display post form at the top of the timeline"
 | 
			
		||||
  suggest-recent-hashtags: "Show recent popular hashtags on the post form"
 | 
			
		||||
@@ -861,7 +866,10 @@ desktop/views/pages/welcome.vue:
 | 
			
		||||
  signin-button: "Logging in..."
 | 
			
		||||
  signup-button: "Sign up"
 | 
			
		||||
  timeline: "Timeline"
 | 
			
		||||
  announcements: "Announcements"
 | 
			
		||||
  photos: "Recent uploaded"
 | 
			
		||||
  powered-by-misskey: "Powered by <b>Misskey</b>."
 | 
			
		||||
  info: "Information"
 | 
			
		||||
desktop/views/pages/drive.vue:
 | 
			
		||||
  title: "Misskey storage"
 | 
			
		||||
desktop/views/pages/favorites.vue:
 | 
			
		||||
@@ -1149,6 +1157,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  dark-mode: "Dark Mode"
 | 
			
		||||
  i-am-under-limited-internet: "I'm in limited bandwidth"
 | 
			
		||||
  circle-icons: "Use circle icons"
 | 
			
		||||
  contrasted-acct: "Add contrast to username"
 | 
			
		||||
  timeline: "Timeline"
 | 
			
		||||
  show-reply-target: "Show reply target"
 | 
			
		||||
  show-my-renotes: "Show my reposts"
 | 
			
		||||
@@ -1157,6 +1166,9 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  post-style: "Post design"
 | 
			
		||||
  post-style-standard: "Standard"
 | 
			
		||||
  post-style-smart: "Smart"
 | 
			
		||||
  notification-position: "Notification style"
 | 
			
		||||
  notification-position-bottom: "Bottom"
 | 
			
		||||
  notification-position-top: "Top"
 | 
			
		||||
  behavior: "Behavior"
 | 
			
		||||
  fetch-on-scroll: "Endless loading on scroll"
 | 
			
		||||
  disable-via-mobile: "Don't mark the post as 'from mobile'"
 | 
			
		||||
@@ -1178,7 +1190,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  settings: "Settings"
 | 
			
		||||
  signout: "Sign out"
 | 
			
		||||
  sound: "Sounds"
 | 
			
		||||
  enableSounds: "Enable sounds"
 | 
			
		||||
  enable-sounds: "Enable sounds"
 | 
			
		||||
mobile/views/pages/user.vue:
 | 
			
		||||
  follows-you: "Follows you"
 | 
			
		||||
  following: "Following"
 | 
			
		||||
 
 | 
			
		||||
@@ -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"
 | 
			
		||||
@@ -647,6 +651,7 @@ desktop/views/components/settings.vue:
 | 
			
		||||
  delete-wallpaper: "Suprimir fondo"
 | 
			
		||||
  dark-mode: "Modo Nocturno"
 | 
			
		||||
  circle-icons: "Usar iconos circulares"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  gradient-window-header: "Usar degradados en las cabeceras de las páginas"
 | 
			
		||||
  post-form-on-timeline: "Mostrar el formulario de las entradas encima de la línea de tiempo"
 | 
			
		||||
  suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
 | 
			
		||||
@@ -766,40 +771,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:
 | 
			
		||||
@@ -861,7 +866,10 @@ desktop/views/pages/welcome.vue:
 | 
			
		||||
  signin-button: "やってる"
 | 
			
		||||
  signup-button: "やる"
 | 
			
		||||
  timeline: "タイムライン"
 | 
			
		||||
  announcements: "お知らせ"
 | 
			
		||||
  photos: "最近の画像"
 | 
			
		||||
  powered-by-misskey: "Powered by <b>Misskey</b>."
 | 
			
		||||
  info: "情報"
 | 
			
		||||
desktop/views/pages/drive.vue:
 | 
			
		||||
  title: "Misskey Drive"
 | 
			
		||||
desktop/views/pages/favorites.vue:
 | 
			
		||||
@@ -1149,6 +1157,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  dark-mode: "ダークモード"
 | 
			
		||||
  i-am-under-limited-internet: "私は通信を制限されている"
 | 
			
		||||
  circle-icons: "円形のアイコンを使用"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  timeline: "タイムライン"
 | 
			
		||||
  show-reply-target: "リプライ先を表示する"
 | 
			
		||||
  show-my-renotes: "自分の行ったRenoteを表示する"
 | 
			
		||||
@@ -1157,6 +1166,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: "「モバイルからの投稿」フラグを付けない"
 | 
			
		||||
@@ -1178,7 +1190,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  settings: "設定"
 | 
			
		||||
  signout: "サインアウト"
 | 
			
		||||
  sound: "サウンド"
 | 
			
		||||
  enableSounds: "サウンドを有効にする"
 | 
			
		||||
  enable-sounds: "サウンドを有効にする"
 | 
			
		||||
mobile/views/pages/user.vue:
 | 
			
		||||
  follows-you: "フォローされています"
 | 
			
		||||
  following: "フォロー"
 | 
			
		||||
 
 | 
			
		||||
@@ -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: "C’est 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"
 | 
			
		||||
@@ -647,6 +651,7 @@ desktop/views/components/settings.vue:
 | 
			
		||||
  delete-wallpaper: "Supprimer le fond d'écran"
 | 
			
		||||
  dark-mode: "Mode nuit"
 | 
			
		||||
  circle-icons: "Utiliser des icônes circulaires"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  gradient-window-header: "Utiliser les dégradés sur la barre de titre de la fenêtre"
 | 
			
		||||
  post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
 | 
			
		||||
  suggest-recent-hashtags: "Afficher les hashtags populaires dans le champs de saisie"
 | 
			
		||||
@@ -861,7 +866,10 @@ desktop/views/pages/welcome.vue:
 | 
			
		||||
  signin-button: "Se connecter"
 | 
			
		||||
  signup-button: "S'inscrire"
 | 
			
		||||
  timeline: "Fil d'actualité"
 | 
			
		||||
  announcements: "お知らせ"
 | 
			
		||||
  photos: "最近の画像"
 | 
			
		||||
  powered-by-misskey: "Propulsé par <b>Misskey</b>."
 | 
			
		||||
  info: "情報"
 | 
			
		||||
desktop/views/pages/drive.vue:
 | 
			
		||||
  title: "Lecteur de Misskey"
 | 
			
		||||
desktop/views/pages/favorites.vue:
 | 
			
		||||
@@ -1149,6 +1157,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  dark-mode: "Mode nuit"
 | 
			
		||||
  i-am-under-limited-internet: "J'ai un accès Internet limité"
 | 
			
		||||
  circle-icons: "Utiliser des icônes circulaires"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  timeline: "Fil d'actualité"
 | 
			
		||||
  show-reply-target: "Afficher les réponses"
 | 
			
		||||
  show-my-renotes: "Afficher mes republications"
 | 
			
		||||
@@ -1157,6 +1166,9 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  post-style: "Style de la publication"
 | 
			
		||||
  post-style-standard: "Standard"
 | 
			
		||||
  post-style-smart: "Intelligent"
 | 
			
		||||
  notification-position: "通知の表示"
 | 
			
		||||
  notification-position-bottom: "下"
 | 
			
		||||
  notification-position-top: "上"
 | 
			
		||||
  behavior: "Comportement"
 | 
			
		||||
  fetch-on-scroll: "Chargement lors du défilement"
 | 
			
		||||
  disable-via-mobile: "Ne pas mentionner que ma publication provient d'un 'périphérique mobile'"
 | 
			
		||||
@@ -1178,7 +1190,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  settings: "Réglages"
 | 
			
		||||
  signout: "Déconnexion"
 | 
			
		||||
  sound: "Sons"
 | 
			
		||||
  enableSounds: "Activer le son"
 | 
			
		||||
  enable-sounds: "サウンドを有効にする"
 | 
			
		||||
mobile/views/pages/user.vue:
 | 
			
		||||
  follows-you: "vous suit"
 | 
			
		||||
  following: "Abonnements"
 | 
			
		||||
 
 | 
			
		||||
@@ -5,24 +5,9 @@
 | 
			
		||||
const fs = require('fs');
 | 
			
		||||
const yaml = require('js-yaml');
 | 
			
		||||
 | 
			
		||||
const loadLang = lang => yaml.safeLoad(
 | 
			
		||||
	fs.readFileSync(`${__dirname}/${lang}.yml`, 'utf-8'));
 | 
			
		||||
const langs = ['de-DE', 'en-US', 'fr-FR', 'ja-JP', 'ja-KS', 'pl-PL', 'es-ES', 'nl-NL'];
 | 
			
		||||
 | 
			
		||||
const native = loadLang('ja-JP');
 | 
			
		||||
const loadLocale = lang => yaml.safeLoad(fs.readFileSync(`${__dirname}/${lang}.yml`, 'utf-8'));
 | 
			
		||||
const locales = langs.map(lang => ({ [lang]: loadLocale(lang) }));
 | 
			
		||||
 | 
			
		||||
const langs = {
 | 
			
		||||
	'de-DE': loadLang('de-DE'),
 | 
			
		||||
	'en-US': loadLang('en-US'),
 | 
			
		||||
	'fr-FR': loadLang('fr-FR'),
 | 
			
		||||
	'ja-JP': native,
 | 
			
		||||
	'ja-KS': loadLang('ja-KS'),
 | 
			
		||||
	'pl-PL': loadLang('pl-PL'),
 | 
			
		||||
	'es-ES': loadLang('es-ES')
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Object.values(langs).forEach(locale => {
 | 
			
		||||
	// Extend native language (Japanese)
 | 
			
		||||
	locale = Object.assign({}, native, locale);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
module.exports = langs;
 | 
			
		||||
module.exports = locales.reduce((a, b) => ({ ...a, ...b }));
 | 
			
		||||
 
 | 
			
		||||
@@ -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: "表示を切り替え"
 | 
			
		||||
@@ -647,6 +651,7 @@ desktop/views/components/settings.vue:
 | 
			
		||||
  delete-wallpaper: "壁紙を削除"
 | 
			
		||||
  dark-mode: "ダークモード"
 | 
			
		||||
  circle-icons: "円形のアイコンを使用"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用"
 | 
			
		||||
  post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
 | 
			
		||||
  suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
 | 
			
		||||
@@ -861,7 +866,10 @@ desktop/views/pages/welcome.vue:
 | 
			
		||||
  signin-button: "やってる"
 | 
			
		||||
  signup-button: "やる"
 | 
			
		||||
  timeline: "タイムライン"
 | 
			
		||||
  announcements: "お知らせ"
 | 
			
		||||
  photos: "最近の画像"
 | 
			
		||||
  powered-by-misskey: "Powered by <b>Misskey</b>."
 | 
			
		||||
  info: "情報"
 | 
			
		||||
desktop/views/pages/drive.vue:
 | 
			
		||||
  title: "Misskey Drive"
 | 
			
		||||
desktop/views/pages/favorites.vue:
 | 
			
		||||
@@ -1149,6 +1157,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  dark-mode: "ダークモード"
 | 
			
		||||
  i-am-under-limited-internet: "私は通信を制限されている"
 | 
			
		||||
  circle-icons: "円形のアイコンを使用"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  timeline: "タイムライン"
 | 
			
		||||
  show-reply-target: "リプライ先を表示する"
 | 
			
		||||
  show-my-renotes: "自分の行ったRenoteを表示する"
 | 
			
		||||
@@ -1157,6 +1166,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: "「モバイルからの投稿」フラグを付けない"
 | 
			
		||||
@@ -1178,7 +1190,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  settings: "設定"
 | 
			
		||||
  signout: "サインアウト"
 | 
			
		||||
  sound: "サウンド"
 | 
			
		||||
  enableSounds: "サウンドを有効にする"
 | 
			
		||||
  enable-sounds: "サウンドを有効にする"
 | 
			
		||||
mobile/views/pages/user.vue:
 | 
			
		||||
  follows-you: "フォローされています"
 | 
			
		||||
  following: "フォロー"
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,19 @@ common:
 | 
			
		||||
  misskey: "A ⭐ of fediverse"
 | 
			
		||||
  about-title: "A ⭐ of fediverse."
 | 
			
		||||
  about: "Misskeyを見つけていただき、ありがとうございます。Misskeyは、地球で生まれた<b>分散マイクロブログSNS</b>です。Fediverse(様々なSNSで構成される宇宙)の中に存在するため、他のSNSと相互に繋がっています。暫し都会の喧騒から離れて、新しいインターネットにダイブしてみませんか。"
 | 
			
		||||
  intro:
 | 
			
		||||
    title: "Misskeyって?"
 | 
			
		||||
    about: "Misskeyはオープンソースの<b>分散型マイクロブログSNS</b>です。リッチで高度にカスタマイズできるUI、投稿へのリアクション、ファイルを一元管理できるドライブなど、先進的な機能を揃えています。また、Fediverseと呼ばれるネットワークに接続できるため、他のSNSともやり取りできます。例えば、あなたが何か投稿すると、その投稿はMisskeyだけでなく他のSNSにも伝わります。ちょうどある惑星から他の惑星に電波を発信している様子をイメージしてください。"
 | 
			
		||||
    features: "特徴"
 | 
			
		||||
    rich-contents: "投稿"
 | 
			
		||||
    rich-contents-desc: "自分の考え、話題の出来事、皆と共有したいことについて発信してください。必要であれば、様々な構文を使って投稿を装飾したり、好きな画像、動画などのファイルやアンケートを添付することもできます。"
 | 
			
		||||
    reaction: "リアクション"
 | 
			
		||||
    reaction-desc: "あなたの気持ちを伝える最も簡単な方法です。Misskeyは、他のユーザーの投稿に様々なリアクションを付けることができます。いちどMisskeyのリアクション機能を体験してしまうと、もう「いいね」の概念しか存在しないSNSには戻れなくなるかもしれません。"
 | 
			
		||||
    ui: "インターフェース"
 | 
			
		||||
    ui-desc: "どのようなUIが使いやすいかは人それぞれです。だから、Misskeyは自由度の高いUIを持っています。レイアウトやデザインを調整したり、カスタマイズ可能な様々なウィジェットを配置したりして、自分だけのホームを作ってください。"
 | 
			
		||||
    drive: "ドライブ"
 | 
			
		||||
    drive-desc: "以前投稿したことのある画像をまた投稿したくなったことはありませんか?もしくは、アップロードしたファイルをフォルダ分けして整理したくなったことはありませんか?Misskeyの根幹に組み込まれたドライブ機能によってそれらが解決します。ファイルの共有も簡単です。"
 | 
			
		||||
    outro: "他にもMisskeyにしかない機能はまだまだあるので、ぜひあなた自身の目で確かめてください。Misskeyは分散型SNSなので、このインスタンスが気に入らなければ他のインスタンスを試すこともできます。それでは、GLHF!"
 | 
			
		||||
  adblock:
 | 
			
		||||
    detected: "広告ブロッカーを無効にしてください"
 | 
			
		||||
    warning: "<strong>Misskeyは広告を掲載していません</strong>が、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。"
 | 
			
		||||
@@ -73,6 +86,16 @@ common:
 | 
			
		||||
    rip: "RIP"
 | 
			
		||||
    pudding: "Pudding"
 | 
			
		||||
 | 
			
		||||
  note-visibility:
 | 
			
		||||
    public: "公開"
 | 
			
		||||
    home: "ホーム"
 | 
			
		||||
    home-desc: "ホームタイムラインにのみ公開"
 | 
			
		||||
    followers: "フォロワー"
 | 
			
		||||
    followers-desc: "自分のフォロワーにのみ公開"
 | 
			
		||||
    specified: "ダイレクト"
 | 
			
		||||
    specified-desc: "指定したユーザーにのみ公開"
 | 
			
		||||
    private: "非公開"
 | 
			
		||||
 | 
			
		||||
  note-placeholders:
 | 
			
		||||
    a: "今どうしてる?"
 | 
			
		||||
    b: "何かありましたか?"
 | 
			
		||||
@@ -375,6 +398,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 +430,6 @@ common/views/widgets/posts-monitor.vue:
 | 
			
		||||
 | 
			
		||||
common/views/widgets/hashtags.vue:
 | 
			
		||||
  title: "ハッシュタグ"
 | 
			
		||||
  count: "{}人が投稿"
 | 
			
		||||
  empty: "トレンドなし"
 | 
			
		||||
 | 
			
		||||
common/views/widgets/server.vue:
 | 
			
		||||
  title: "サーバー情報"
 | 
			
		||||
@@ -722,6 +747,9 @@ desktop/views/components/settings.vue:
 | 
			
		||||
  behaviour: "動作"
 | 
			
		||||
  fetch-on-scroll: "スクロールで自動読み込み"
 | 
			
		||||
  fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。"
 | 
			
		||||
  note-visibility: "投稿の公開範囲"
 | 
			
		||||
  default-note-visibility: "デフォルトの公開範囲"
 | 
			
		||||
  remember-note-visibility: "投稿の公開範囲を記憶する"
 | 
			
		||||
  auto-popout: "ウィンドウの自動ポップアウト"
 | 
			
		||||
  auto-popout-desc: "ウィンドウが開かれるとき、ポップアウト(ブラウザ外に切り離す)可能なら自動でポップアウトします。この設定はブラウザに記憶されます。"
 | 
			
		||||
  advanced: "詳細設定"
 | 
			
		||||
@@ -734,6 +762,7 @@ desktop/views/components/settings.vue:
 | 
			
		||||
  delete-wallpaper: "壁紙を削除"
 | 
			
		||||
  dark-mode: "ダークモード"
 | 
			
		||||
  circle-icons: "円形のアイコンを使用"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用"
 | 
			
		||||
  post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
 | 
			
		||||
  suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
 | 
			
		||||
@@ -988,7 +1017,10 @@ desktop/views/pages/welcome.vue:
 | 
			
		||||
  signin-button: "やってる"
 | 
			
		||||
  signup-button: "やる"
 | 
			
		||||
  timeline: "タイムライン"
 | 
			
		||||
  announcements: "お知らせ"
 | 
			
		||||
  photos: "最近の画像"
 | 
			
		||||
  powered-by-misskey: "Powered by <b>Misskey</b>."
 | 
			
		||||
  info: "情報"
 | 
			
		||||
 | 
			
		||||
desktop/views/pages/drive.vue:
 | 
			
		||||
  title: "Misskey Drive"
 | 
			
		||||
@@ -1345,6 +1377,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  dark-mode: "ダークモード"
 | 
			
		||||
  i-am-under-limited-internet: "私は通信を制限されている"
 | 
			
		||||
  circle-icons: "円形のアイコンを使用"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  timeline: "タイムライン"
 | 
			
		||||
  show-reply-target: "リプライ先を表示する"
 | 
			
		||||
  show-my-renotes: "自分の行ったRenoteを表示する"
 | 
			
		||||
@@ -1353,8 +1386,14 @@ 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: "スクロールで自動読み込み"
 | 
			
		||||
  note-visibility: "投稿の公開範囲"
 | 
			
		||||
  default-note-visibility: "デフォルトの公開範囲"
 | 
			
		||||
  remember-note-visibility: "投稿の公開範囲を記憶する"
 | 
			
		||||
  disable-via-mobile: "「モバイルからの投稿」フラグを付けない"
 | 
			
		||||
  load-raw-images: "添付された画像を高画質で表示する"
 | 
			
		||||
  load-remote-media: "リモートサーバーのメディアを表示する"
 | 
			
		||||
@@ -1374,7 +1413,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  settings: "設定"
 | 
			
		||||
  signout: "サインアウト"
 | 
			
		||||
  sound: "サウンド"
 | 
			
		||||
  enableSounds: "サウンドを有効にする"
 | 
			
		||||
  enable-sounds: "サウンドを有効にする"
 | 
			
		||||
 | 
			
		||||
mobile/views/pages/user.vue:
 | 
			
		||||
  follows-you: "フォローされています"
 | 
			
		||||
 
 | 
			
		||||
@@ -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: "表示を切り替え"
 | 
			
		||||
@@ -647,6 +651,7 @@ desktop/views/components/settings.vue:
 | 
			
		||||
  delete-wallpaper: "壁紙を削除"
 | 
			
		||||
  dark-mode: "ダークモード"
 | 
			
		||||
  circle-icons: "円形のアイコンを使用"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用"
 | 
			
		||||
  post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
 | 
			
		||||
  suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
 | 
			
		||||
@@ -861,7 +866,10 @@ desktop/views/pages/welcome.vue:
 | 
			
		||||
  signin-button: "サインイン中…"
 | 
			
		||||
  signup-button: "サインアップ"
 | 
			
		||||
  timeline: "タイムライン"
 | 
			
		||||
  announcements: "お知らせ"
 | 
			
		||||
  photos: "最近の画像"
 | 
			
		||||
  powered-by-misskey: "Powered by <b>Misskey</b>."
 | 
			
		||||
  info: "情報"
 | 
			
		||||
desktop/views/pages/drive.vue:
 | 
			
		||||
  title: "ドライブ"
 | 
			
		||||
desktop/views/pages/favorites.vue:
 | 
			
		||||
@@ -1149,6 +1157,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  dark-mode: "ダークモード"
 | 
			
		||||
  i-am-under-limited-internet: "私は通信を制限されている"
 | 
			
		||||
  circle-icons: "円形のアイコンを使用"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  timeline: "タイムライン"
 | 
			
		||||
  show-reply-target: "リプライ先を表示する"
 | 
			
		||||
  show-my-renotes: "自分の行ったRenoteを表示する"
 | 
			
		||||
@@ -1157,6 +1166,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: "「モバイルからの投稿」フラグを付けない"
 | 
			
		||||
@@ -1178,7 +1190,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  settings: "設定"
 | 
			
		||||
  signout: "サインアウト"
 | 
			
		||||
  sound: "サウンド"
 | 
			
		||||
  enableSounds: "サウンドを有効にする"
 | 
			
		||||
  enable-sounds: "サウンドを有効にする"
 | 
			
		||||
mobile/views/pages/user.vue:
 | 
			
		||||
  follows-you: "フォローされています"
 | 
			
		||||
  following: "フォロー"
 | 
			
		||||
 
 | 
			
		||||
@@ -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: "表示を切り替え"
 | 
			
		||||
@@ -647,6 +651,7 @@ desktop/views/components/settings.vue:
 | 
			
		||||
  delete-wallpaper: "壁紙を削除"
 | 
			
		||||
  dark-mode: "ダークモード"
 | 
			
		||||
  circle-icons: "円形のアイコンを使用"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用"
 | 
			
		||||
  post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
 | 
			
		||||
  suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
 | 
			
		||||
@@ -861,7 +866,10 @@ desktop/views/pages/welcome.vue:
 | 
			
		||||
  signin-button: "やってる"
 | 
			
		||||
  signup-button: "やる"
 | 
			
		||||
  timeline: "タイムライン"
 | 
			
		||||
  announcements: "お知らせ"
 | 
			
		||||
  photos: "最近の画像"
 | 
			
		||||
  powered-by-misskey: "Powered by <b>Misskey</b>."
 | 
			
		||||
  info: "情報"
 | 
			
		||||
desktop/views/pages/drive.vue:
 | 
			
		||||
  title: "Misskey Drive"
 | 
			
		||||
desktop/views/pages/favorites.vue:
 | 
			
		||||
@@ -1149,6 +1157,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  dark-mode: "ダークモード"
 | 
			
		||||
  i-am-under-limited-internet: "私は通信を制限されている"
 | 
			
		||||
  circle-icons: "円形のアイコンを使用"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  timeline: "タイムライン"
 | 
			
		||||
  show-reply-target: "リプライ先を表示する"
 | 
			
		||||
  show-my-renotes: "自分の行ったRenoteを表示する"
 | 
			
		||||
@@ -1157,6 +1166,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: "「モバイルからの投稿」フラグを付けない"
 | 
			
		||||
@@ -1178,7 +1190,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  settings: "設定"
 | 
			
		||||
  signout: "サインアウト"
 | 
			
		||||
  sound: "サウンド"
 | 
			
		||||
  enableSounds: "サウンドを有効にする"
 | 
			
		||||
  enable-sounds: "サウンドを有効にする"
 | 
			
		||||
mobile/views/pages/user.vue:
 | 
			
		||||
  follows-you: "フォローされています"
 | 
			
		||||
  following: "フォロー"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1249
									
								
								locales/nl-NL.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1249
									
								
								locales/nl-NL.yml
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1249
									
								
								locales/no-NO.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1249
									
								
								locales/no-NO.yml
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -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"
 | 
			
		||||
@@ -647,6 +651,7 @@ desktop/views/components/settings.vue:
 | 
			
		||||
  delete-wallpaper: "Usuń tło"
 | 
			
		||||
  dark-mode: "Tryb ciemny"
 | 
			
		||||
  circle-icons: "Używaj okrągłych ikon"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  gradient-window-header: "Używaj gradientów na pasku tytułu okna"
 | 
			
		||||
  post-form-on-timeline: "Wyświetlaj formularz tworzenia wpisu w górnej części osi czasu"
 | 
			
		||||
  suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
 | 
			
		||||
@@ -861,7 +866,10 @@ desktop/views/pages/welcome.vue:
 | 
			
		||||
  signin-button: "Zaloguj się"
 | 
			
		||||
  signup-button: "Zarejestruj się"
 | 
			
		||||
  timeline: "Oś czasu"
 | 
			
		||||
  announcements: "お知らせ"
 | 
			
		||||
  photos: "最近の画像"
 | 
			
		||||
  powered-by-misskey: "Oparto o <b>Misskey</b>."
 | 
			
		||||
  info: "情報"
 | 
			
		||||
desktop/views/pages/drive.vue:
 | 
			
		||||
  title: "Dysk Misskey"
 | 
			
		||||
desktop/views/pages/favorites.vue:
 | 
			
		||||
@@ -1149,6 +1157,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  dark-mode: "Tryb ciemny"
 | 
			
		||||
  i-am-under-limited-internet: "Ograniczaj zużycie transferu"
 | 
			
		||||
  circle-icons: "Używaj okrągłych ikon"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  timeline: "Oś czasu"
 | 
			
		||||
  show-reply-target: "Pokazuj cel odpowiedzi"
 | 
			
		||||
  show-my-renotes: "Pokazuj moje udostępnienia"
 | 
			
		||||
@@ -1157,6 +1166,9 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  post-style: "Styl wpisów"
 | 
			
		||||
  post-style-standard: "Standardowy"
 | 
			
		||||
  post-style-smart: "Inteligentny"
 | 
			
		||||
  notification-position: "通知の表示"
 | 
			
		||||
  notification-position-bottom: "下"
 | 
			
		||||
  notification-position-top: "上"
 | 
			
		||||
  behavior: "Zachowanie"
 | 
			
		||||
  fetch-on-scroll: "Automatycznie ładuj po przeciągnięciu w dół"
 | 
			
		||||
  disable-via-mobile: "Nie oznaczaj wpisów jako „wysłane z telefonu”"
 | 
			
		||||
@@ -1178,7 +1190,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  settings: "Ustawienia"
 | 
			
		||||
  signout: "Wyloguj"
 | 
			
		||||
  sound: "サウンド"
 | 
			
		||||
  enableSounds: "サウンドを有効にする"
 | 
			
		||||
  enable-sounds: "サウンドを有効にする"
 | 
			
		||||
mobile/views/pages/user.vue:
 | 
			
		||||
  follows-you: "Śledzi Cię"
 | 
			
		||||
  following: "Śledzeni"
 | 
			
		||||
 
 | 
			
		||||
@@ -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: "表示を切り替え"
 | 
			
		||||
@@ -647,6 +651,7 @@ desktop/views/components/settings.vue:
 | 
			
		||||
  delete-wallpaper: "壁紙を削除"
 | 
			
		||||
  dark-mode: "ダークモード"
 | 
			
		||||
  circle-icons: "円形のアイコンを使用"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用"
 | 
			
		||||
  post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
 | 
			
		||||
  suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
 | 
			
		||||
@@ -861,7 +866,10 @@ desktop/views/pages/welcome.vue:
 | 
			
		||||
  signin-button: "やってる"
 | 
			
		||||
  signup-button: "やる"
 | 
			
		||||
  timeline: "Timeline"
 | 
			
		||||
  announcements: "お知らせ"
 | 
			
		||||
  photos: "最近の画像"
 | 
			
		||||
  powered-by-misskey: "Desenvolvido por <b>Misskey</b>."
 | 
			
		||||
  info: "情報"
 | 
			
		||||
desktop/views/pages/drive.vue:
 | 
			
		||||
  title: "Drive Misskey"
 | 
			
		||||
desktop/views/pages/favorites.vue:
 | 
			
		||||
@@ -1149,6 +1157,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  dark-mode: "ダークモード"
 | 
			
		||||
  i-am-under-limited-internet: "私は通信を制限されている"
 | 
			
		||||
  circle-icons: "円形のアイコンを使用"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  timeline: "タイムライン"
 | 
			
		||||
  show-reply-target: "リプライ先を表示する"
 | 
			
		||||
  show-my-renotes: "自分の行ったRenoteを表示する"
 | 
			
		||||
@@ -1157,6 +1166,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: "「モバイルからの投稿」フラグを付けない"
 | 
			
		||||
@@ -1178,7 +1190,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  settings: "設定"
 | 
			
		||||
  signout: "サインアウト"
 | 
			
		||||
  sound: "サウンド"
 | 
			
		||||
  enableSounds: "サウンドを有効にする"
 | 
			
		||||
  enable-sounds: "サウンドを有効にする"
 | 
			
		||||
mobile/views/pages/user.vue:
 | 
			
		||||
  follows-you: "フォローされています"
 | 
			
		||||
  following: "フォロー"
 | 
			
		||||
 
 | 
			
		||||
@@ -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: "表示を切り替え"
 | 
			
		||||
@@ -647,6 +651,7 @@ desktop/views/components/settings.vue:
 | 
			
		||||
  delete-wallpaper: "壁紙を削除"
 | 
			
		||||
  dark-mode: "ダークモード"
 | 
			
		||||
  circle-icons: "円形のアイコンを使用"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用"
 | 
			
		||||
  post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
 | 
			
		||||
  suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
 | 
			
		||||
@@ -861,7 +866,10 @@ desktop/views/pages/welcome.vue:
 | 
			
		||||
  signin-button: "やってる"
 | 
			
		||||
  signup-button: "やる"
 | 
			
		||||
  timeline: "タイムライン"
 | 
			
		||||
  announcements: "お知らせ"
 | 
			
		||||
  photos: "最近の画像"
 | 
			
		||||
  powered-by-misskey: "Powered by <b>Misskey</b>."
 | 
			
		||||
  info: "情報"
 | 
			
		||||
desktop/views/pages/drive.vue:
 | 
			
		||||
  title: "Misskey Drive"
 | 
			
		||||
desktop/views/pages/favorites.vue:
 | 
			
		||||
@@ -1149,6 +1157,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  dark-mode: "ダークモード"
 | 
			
		||||
  i-am-under-limited-internet: "私は通信を制限されている"
 | 
			
		||||
  circle-icons: "円形のアイコンを使用"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  timeline: "タイムライン"
 | 
			
		||||
  show-reply-target: "リプライ先を表示する"
 | 
			
		||||
  show-my-renotes: "自分の行ったRenoteを表示する"
 | 
			
		||||
@@ -1157,6 +1166,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: "「モバイルからの投稿」フラグを付けない"
 | 
			
		||||
@@ -1178,7 +1190,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  settings: "設定"
 | 
			
		||||
  signout: "サインアウト"
 | 
			
		||||
  sound: "サウンド"
 | 
			
		||||
  enableSounds: "サウンドを有効にする"
 | 
			
		||||
  enable-sounds: "サウンドを有効にする"
 | 
			
		||||
mobile/views/pages/user.vue:
 | 
			
		||||
  follows-you: "フォローされています"
 | 
			
		||||
  following: "フォロー"
 | 
			
		||||
 
 | 
			
		||||
@@ -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: "表示を切り替え"
 | 
			
		||||
@@ -647,6 +651,7 @@ desktop/views/components/settings.vue:
 | 
			
		||||
  delete-wallpaper: "壁紙を削除"
 | 
			
		||||
  dark-mode: "ダークモード"
 | 
			
		||||
  circle-icons: "円形のアイコンを使用"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用"
 | 
			
		||||
  post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
 | 
			
		||||
  suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
 | 
			
		||||
@@ -861,7 +866,10 @@ desktop/views/pages/welcome.vue:
 | 
			
		||||
  signin-button: "やってる"
 | 
			
		||||
  signup-button: "やる"
 | 
			
		||||
  timeline: "タイムライン"
 | 
			
		||||
  announcements: "お知らせ"
 | 
			
		||||
  photos: "最近の画像"
 | 
			
		||||
  powered-by-misskey: "Powered by <b>Misskey</b>."
 | 
			
		||||
  info: "情報"
 | 
			
		||||
desktop/views/pages/drive.vue:
 | 
			
		||||
  title: "Misskey Drive"
 | 
			
		||||
desktop/views/pages/favorites.vue:
 | 
			
		||||
@@ -1149,6 +1157,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  dark-mode: "ダークモード"
 | 
			
		||||
  i-am-under-limited-internet: "私は通信を制限されている"
 | 
			
		||||
  circle-icons: "円形のアイコンを使用"
 | 
			
		||||
  contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
  timeline: "タイムライン"
 | 
			
		||||
  show-reply-target: "リプライ先を表示する"
 | 
			
		||||
  show-my-renotes: "自分の行ったRenoteを表示する"
 | 
			
		||||
@@ -1157,6 +1166,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: "「モバイルからの投稿」フラグを付けない"
 | 
			
		||||
@@ -1178,7 +1190,7 @@ mobile/views/pages/settings.vue:
 | 
			
		||||
  settings: "設定"
 | 
			
		||||
  signout: "サインアウト"
 | 
			
		||||
  sound: "サウンド"
 | 
			
		||||
  enableSounds: "サウンドを有効にする"
 | 
			
		||||
  enable-sounds: "サウンドを有効にする"
 | 
			
		||||
mobile/views/pages/user.vue:
 | 
			
		||||
  follows-you: "フォローされています"
 | 
			
		||||
  following: "フォロー"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								package.json
									
									
									
									
									
								
							@@ -1,8 +1,8 @@
 | 
			
		||||
{
 | 
			
		||||
	"name": "misskey",
 | 
			
		||||
	"author": "syuilo <i@syuilo.com>",
 | 
			
		||||
	"version": "8.19.0",
 | 
			
		||||
	"clientVersion": "1.0.9217",
 | 
			
		||||
	"version": "8.32.0",
 | 
			
		||||
	"clientVersion": "1.0.9489",
 | 
			
		||||
	"codename": "nighthike",
 | 
			
		||||
	"main": "./built/index.js",
 | 
			
		||||
	"private": true,
 | 
			
		||||
@@ -55,7 +55,7 @@
 | 
			
		||||
		"@types/koa-send": "4.1.1",
 | 
			
		||||
		"@types/koa-views": "2.0.3",
 | 
			
		||||
		"@types/koa__cors": "2.2.3",
 | 
			
		||||
		"@types/minio": "6.0.2",
 | 
			
		||||
		"@types/minio": "7.0.0",
 | 
			
		||||
		"@types/mkdirp": "0.5.2",
 | 
			
		||||
		"@types/mocha": "5.2.3",
 | 
			
		||||
		"@types/mongodb": "3.1.4",
 | 
			
		||||
@@ -80,7 +80,7 @@
 | 
			
		||||
		"@types/webpack": "4.4.11",
 | 
			
		||||
		"@types/webpack-stream": "3.2.10",
 | 
			
		||||
		"@types/websocket": "0.0.40",
 | 
			
		||||
		"@types/ws": "6.0.0",
 | 
			
		||||
		"@types/ws": "6.0.1",
 | 
			
		||||
		"animejs": "2.2.0",
 | 
			
		||||
		"autosize": "4.0.2",
 | 
			
		||||
		"autwh": "0.1.0",
 | 
			
		||||
@@ -151,7 +151,7 @@
 | 
			
		||||
		"lodash.assign": "4.2.0",
 | 
			
		||||
		"mecab-async": "0.1.2",
 | 
			
		||||
		"merge-options": "1.0.1",
 | 
			
		||||
		"minio": "7.0.0",
 | 
			
		||||
		"minio": "7.0.1",
 | 
			
		||||
		"mkdirp": "0.5.1",
 | 
			
		||||
		"mocha": "5.2.0",
 | 
			
		||||
		"moji": "0.5.1",
 | 
			
		||||
@@ -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.1",
 | 
			
		||||
		"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.1",
 | 
			
		||||
		"syuilo-password-strength": "0.0.1",
 | 
			
		||||
		"textarea-caret": "3.1.0",
 | 
			
		||||
		"tmp": "0.0.33",
 | 
			
		||||
@@ -210,19 +210,19 @@
 | 
			
		||||
		"vue": "2.5.17",
 | 
			
		||||
		"vue-chartjs": "3.4.0",
 | 
			
		||||
		"vue-cropperjs": "2.2.1",
 | 
			
		||||
		"vue-js-modal": "1.3.24",
 | 
			
		||||
		"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",
 | 
			
		||||
		"vuewordcloud": "18.7.11",
 | 
			
		||||
		"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",
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,10 @@ html
 | 
			
		||||
		&, *
 | 
			
		||||
			cursor progress !important
 | 
			
		||||
 | 
			
		||||
html
 | 
			
		||||
	// iOSのため
 | 
			
		||||
	overflow auto
 | 
			
		||||
 | 
			
		||||
body
 | 
			
		||||
	overflow-wrap break-word
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,3 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div>
 | 
			
		||||
	<router-view id="app"></router-view>
 | 
			
		||||
	<modal-portal/>
 | 
			
		||||
</div>
 | 
			
		||||
<router-view id="app"></router-view>
 | 
			
		||||
</template>
 | 
			
		||||
 
 | 
			
		||||
@@ -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}`;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -94,7 +94,7 @@
 | 
			
		||||
 | 
			
		||||
	// Get salt query
 | 
			
		||||
	const salt = localStorage.getItem('salt')
 | 
			
		||||
		? '?salt=' + localStorage.getItem('salt')
 | 
			
		||||
		? `?salt=${localStorage.getItem('salt')}`
 | 
			
		||||
		: '';
 | 
			
		||||
 | 
			
		||||
	// Load an app script
 | 
			
		||||
@@ -140,7 +140,7 @@
 | 
			
		||||
		// Random
 | 
			
		||||
		localStorage.setItem('salt', Math.random().toString());
 | 
			
		||||
 | 
			
		||||
		// Clear cache (serive worker)
 | 
			
		||||
		// Clear cache (service worker)
 | 
			
		||||
		try {
 | 
			
		||||
			navigator.serviceWorker.controller.postMessage('clear');
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@ export default async function(mios: MiOS, force = false, silent = false) {
 | 
			
		||||
		localStorage.setItem('should-refresh', 'true');
 | 
			
		||||
		localStorage.setItem('v', newer);
 | 
			
		||||
 | 
			
		||||
		// Clear cache (serive worker)
 | 
			
		||||
		// Clear cache (service worker)
 | 
			
		||||
		try {
 | 
			
		||||
			if (navigator.serviceWorker.controller) {
 | 
			
		||||
				navigator.serviceWorker.controller.postMessage('clear');
 | 
			
		||||
 
 | 
			
		||||
@@ -1,2 +0,0 @@
 | 
			
		||||
const gcd = (a, b) => !b ? a : gcd(b, a % b);
 | 
			
		||||
export default gcd;
 | 
			
		||||
@@ -1,53 +0,0 @@
 | 
			
		||||
export default function(qs: string) {
 | 
			
		||||
	const q = {
 | 
			
		||||
		text: ''
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	qs.split(' ').forEach(x => {
 | 
			
		||||
		if (/^([a-z_]+?):(.+?)$/.test(x)) {
 | 
			
		||||
			const [key, value] = x.split(':');
 | 
			
		||||
			switch (key) {
 | 
			
		||||
				case 'user':
 | 
			
		||||
					q['includeUserUsernames'] = value.split(',');
 | 
			
		||||
					break;
 | 
			
		||||
				case 'exclude_user':
 | 
			
		||||
					q['excludeUserUsernames'] = value.split(',');
 | 
			
		||||
					break;
 | 
			
		||||
				case 'follow':
 | 
			
		||||
					q['following'] = value == 'null' ? null : value == 'true';
 | 
			
		||||
					break;
 | 
			
		||||
				case 'reply':
 | 
			
		||||
					q['reply'] = value == 'null' ? null : value == 'true';
 | 
			
		||||
					break;
 | 
			
		||||
				case 'renote':
 | 
			
		||||
					q['renote'] = value == 'null' ? null : value == 'true';
 | 
			
		||||
					break;
 | 
			
		||||
				case 'media':
 | 
			
		||||
					q['media'] = value == 'null' ? null : value == 'true';
 | 
			
		||||
					break;
 | 
			
		||||
				case 'poll':
 | 
			
		||||
					q['poll'] = value == 'null' ? null : value == 'true';
 | 
			
		||||
					break;
 | 
			
		||||
				case 'until':
 | 
			
		||||
				case 'since':
 | 
			
		||||
					// YYYY-MM-DD
 | 
			
		||||
					if (/^[0-9]+\-[0-9]+\-[0-9]+$/) {
 | 
			
		||||
						const [yyyy, mm, dd] = value.split('-');
 | 
			
		||||
						q[`${key}_date`] = (new Date(parseInt(yyyy, 10), parseInt(mm, 10) - 1, parseInt(dd, 10))).getTime();
 | 
			
		||||
					}
 | 
			
		||||
					break;
 | 
			
		||||
				default:
 | 
			
		||||
					q[key] = value;
 | 
			
		||||
					break;
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			q.text += x + ' ';
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	if (q.text) {
 | 
			
		||||
		q.text = q.text.trim();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return q;
 | 
			
		||||
}
 | 
			
		||||
@@ -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
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
		});
 | 
			
		||||
		} : {});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
import { EventEmitter } from 'eventemitter3';
 | 
			
		||||
import * as uuid from 'uuid';
 | 
			
		||||
import Connection from './stream';
 | 
			
		||||
import { erase } from '../../../../../prelude/array';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ストリーム接続を管理するクラス
 | 
			
		||||
@@ -89,7 +90,7 @@ export default abstract class StreamManager<T extends Connection> extends EventE
 | 
			
		||||
	 * @param userId use で発行したユーザーID
 | 
			
		||||
	 */
 | 
			
		||||
	public dispose(userId) {
 | 
			
		||||
		this.users = this.users.filter(id => id != userId);
 | 
			
		||||
		this.users = erase(userId, this.users);
 | 
			
		||||
 | 
			
		||||
		this._connection.user = `Managed (${ this.users.length })`;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,19 +1,25 @@
 | 
			
		||||
<template>
 | 
			
		||||
<span class="mk-acct">
 | 
			
		||||
	<span class="name">@{{ user.username }}</span>
 | 
			
		||||
	<span class="host" v-if="user.host">@{{ user.host }}</span>
 | 
			
		||||
	<span class="host" :class="{ fade: $store.state.settings.contrastedAcct }" v-if="user.host || detail">@{{ user.host || host }}</span>
 | 
			
		||||
</span>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import { host } from '../../../config';
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	props: ['user']
 | 
			
		||||
	props: ['user', 'detail'],
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			host
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
.mk-acct
 | 
			
		||||
	> .host
 | 
			
		||||
	> .host.fade
 | 
			
		||||
		opacity 0.5
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
 | 
			
		||||
import tagCloud from './tag-cloud.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 +42,8 @@ import uiSelect from './ui/select.vue';
 | 
			
		||||
import formButton from './ui/form/button.vue';
 | 
			
		||||
import formRadio from './ui/form/radio.vue';
 | 
			
		||||
 | 
			
		||||
Vue.component('mk-tag-cloud', tagCloud);
 | 
			
		||||
Vue.component('mk-trends', trends);
 | 
			
		||||
Vue.component('mk-analog-clock', analogClock);
 | 
			
		||||
Vue.component('mk-menu', menu);
 | 
			
		||||
Vue.component('mk-note-header', noteHeader);
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,7 @@
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import { erase } from '../../../../../prelude/array';
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
@@ -53,7 +54,7 @@ export default Vue.extend({
 | 
			
		||||
 | 
			
		||||
		get() {
 | 
			
		||||
			return {
 | 
			
		||||
				choices: this.choices.filter(choice => choice != '')
 | 
			
		||||
				choices: erase('', this.choices)
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,7 @@
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import { sum } from '../../../../../prelude/array';
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	props: ['note'],
 | 
			
		||||
	data() {
 | 
			
		||||
@@ -33,7 +34,7 @@ export default Vue.extend({
 | 
			
		||||
			return this.note.poll;
 | 
			
		||||
		},
 | 
			
		||||
		total(): number {
 | 
			
		||||
			return this.poll.choices.reduce((a, b) => a + b.votes, 0);
 | 
			
		||||
			return sum(this.poll.choices.map(x => x.votes));
 | 
			
		||||
		},
 | 
			
		||||
		isVoted(): boolean {
 | 
			
		||||
			return this.poll.choices.some(c => c.isVoted);
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										90
									
								
								src/client/app/common/views/components/tag-cloud.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								src/client/app/common/views/components/tag-cloud.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div class="jtivnzhfwquxpsfidertopbmwmchmnmo">
 | 
			
		||||
	<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
 | 
			
		||||
	<p class="empty" v-else-if="tags.length == 0">%fa:exclamation-circle%%i18n:@empty%</p>
 | 
			
		||||
	<div v-else>
 | 
			
		||||
		<vue-word-cloud
 | 
			
		||||
				:words="tags.slice(0, 20).map(x => [x.name, x.count])"
 | 
			
		||||
				:color="color"
 | 
			
		||||
				:spacing="1">
 | 
			
		||||
			<template slot-scope="{word, text, weight}">
 | 
			
		||||
				<div style="cursor: pointer;" :title="weight">
 | 
			
		||||
					{{ text }}
 | 
			
		||||
				</div>
 | 
			
		||||
			</template>
 | 
			
		||||
		</vue-word-cloud>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import * as VueWordCloud from 'vuewordcloud';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	components: {
 | 
			
		||||
		[VueWordCloud.name]: VueWordCloud
 | 
			
		||||
	},
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			tags: [],
 | 
			
		||||
			fetching: true,
 | 
			
		||||
			clock: null
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.fetch();
 | 
			
		||||
		this.clock = setInterval(this.fetch, 1000 * 60);
 | 
			
		||||
	},
 | 
			
		||||
	beforeDestroy() {
 | 
			
		||||
		clearInterval(this.clock);
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		fetch() {
 | 
			
		||||
			(this as any).api('aggregation/hashtags').then(tags => {
 | 
			
		||||
				this.tags = tags;
 | 
			
		||||
				this.fetching = false;
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		color([, weight]) {
 | 
			
		||||
			const peak = Math.max.apply(null, this.tags.map(x => x.count));
 | 
			
		||||
			const w = weight / peak;
 | 
			
		||||
 | 
			
		||||
			if (w > 0.9) {
 | 
			
		||||
				return this.$store.state.device.darkmode ? '#ff4e69' : '#ff4e69';
 | 
			
		||||
			} else if (w > 0.5) {
 | 
			
		||||
				return this.$store.state.device.darkmode ? '#3bc4c7' : '#3bc4c7';
 | 
			
		||||
			} else {
 | 
			
		||||
				return this.$store.state.device.darkmode ? '#fff' : '#555';
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
root(isDark)
 | 
			
		||||
	height 100%
 | 
			
		||||
	width 100%
 | 
			
		||||
 | 
			
		||||
	> .fetching
 | 
			
		||||
	> .empty
 | 
			
		||||
		margin 0
 | 
			
		||||
		padding 16px
 | 
			
		||||
		text-align center
 | 
			
		||||
		color #aaa
 | 
			
		||||
 | 
			
		||||
		> [data-fa]
 | 
			
		||||
			margin-right 4px
 | 
			
		||||
 | 
			
		||||
	> div
 | 
			
		||||
		height 100%
 | 
			
		||||
		width 100%
 | 
			
		||||
 | 
			
		||||
.jtivnzhfwquxpsfidertopbmwmchmnmo[data-darkmode]
 | 
			
		||||
	root(true)
 | 
			
		||||
 | 
			
		||||
.jtivnzhfwquxpsfidertopbmwmchmnmo:not([data-darkmode])
 | 
			
		||||
	root(false)
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										105
									
								
								src/client/app/common/views/components/trends.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								src/client/app/common/views/components/trends.vue
									
									
									
									
									
										Normal 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>
 | 
			
		||||
@@ -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)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@
 | 
			
		||||
			<header>
 | 
			
		||||
				<h1>{{ title }}</h1>
 | 
			
		||||
			</header>
 | 
			
		||||
			<p>{{ description }}</p>
 | 
			
		||||
			<p>{{ description.length > 85 ? description.slice(0, 85) + '…' : description }}</p>
 | 
			
		||||
			<footer>
 | 
			
		||||
				<img class="icon" v-if="icon" :src="icon"/>
 | 
			
		||||
				<p>{{ sitename }}</p>
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ export default Vue.extend({
 | 
			
		||||
	props: ['source', 'compact'],
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			v: this.$store.state.device.visibility || 'public'
 | 
			
		||||
			v: this.$store.state.settings.rememberNoteVisibility ? (this.$store.state.device.visibility || this.$store.state.settings.defaultNoteVisibility) : this.$store.state.settings.defaultNoteVisibility
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
@@ -97,7 +97,9 @@ export default Vue.extend({
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		choose(visibility) {
 | 
			
		||||
			this.$store.commit('device/setVisibility', visibility);
 | 
			
		||||
			if (this.$store.state.settings.rememberNoteVisibility) {
 | 
			
		||||
				this.$store.commit('device/setVisibility', visibility);
 | 
			
		||||
			}
 | 
			
		||||
			this.$emit('chosen', visibility);
 | 
			
		||||
			this.$destroy();
 | 
			
		||||
		},
 | 
			
		||||
 
 | 
			
		||||
@@ -1,22 +1,24 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div class="mk-welcome-timeline">
 | 
			
		||||
	<div v-for="note in notes">
 | 
			
		||||
		<mk-avatar class="avatar" :user="note.user" target="_blank"/>
 | 
			
		||||
		<div class="body">
 | 
			
		||||
			<header>
 | 
			
		||||
				<router-link class="name" :to="note.user | userPage" v-user-preview="note.user.id">{{ note.user | userName }}</router-link>
 | 
			
		||||
				<span class="username">@{{ note.user | acct }}</span>
 | 
			
		||||
				<div class="info">
 | 
			
		||||
					<router-link class="created-at" :to="note | notePage">
 | 
			
		||||
						<mk-time :time="note.createdAt"/>
 | 
			
		||||
					</router-link>
 | 
			
		||||
	<transition-group name="ldzpakcixzickvggyixyrhqwjaefknon" tag="div">
 | 
			
		||||
		<div v-for="note in notes" :key="note.id">
 | 
			
		||||
			<mk-avatar class="avatar" :user="note.user" target="_blank"/>
 | 
			
		||||
			<div class="body">
 | 
			
		||||
				<header>
 | 
			
		||||
					<router-link class="name" :to="note.user | userPage" v-user-preview="note.user.id">{{ note.user | userName }}</router-link>
 | 
			
		||||
					<span class="username">@{{ note.user | acct }}</span>
 | 
			
		||||
					<div class="info">
 | 
			
		||||
						<router-link class="created-at" :to="note | notePage">
 | 
			
		||||
							<mk-time :time="note.createdAt"/>
 | 
			
		||||
						</router-link>
 | 
			
		||||
					</div>
 | 
			
		||||
				</header>
 | 
			
		||||
				<div class="text">
 | 
			
		||||
					<misskey-flavored-markdown v-if="note.text" :text="note.text"/>
 | 
			
		||||
				</div>
 | 
			
		||||
			</header>
 | 
			
		||||
			<div class="text">
 | 
			
		||||
				<misskey-flavored-markdown v-if="note.text" :text="note.text"/>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
	</transition-group>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
@@ -31,15 +33,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;
 | 
			
		||||
@@ -48,77 +65,93 @@ export default Vue.extend({
 | 
			
		||||
				local: true,
 | 
			
		||||
				reply: false,
 | 
			
		||||
				renote: false,
 | 
			
		||||
				media: false,
 | 
			
		||||
				poll: false,
 | 
			
		||||
				bot: false
 | 
			
		||||
				file: 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>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
.ldzpakcixzickvggyixyrhqwjaefknon-enter
 | 
			
		||||
.ldzpakcixzickvggyixyrhqwjaefknon-leave-to
 | 
			
		||||
	opacity 0
 | 
			
		||||
	transform translateY(-30px)
 | 
			
		||||
 | 
			
		||||
root(isDark)
 | 
			
		||||
	background isDark ? #282C37 : #fff
 | 
			
		||||
 | 
			
		||||
	> div
 | 
			
		||||
		padding 16px
 | 
			
		||||
		overflow-wrap break-word
 | 
			
		||||
		font-size .9em
 | 
			
		||||
		color isDark ? #fff : #4C4C4C
 | 
			
		||||
		border-bottom 1px solid isDark ? rgba(#000, 0.1) : rgba(#000, 0.05)
 | 
			
		||||
		> *
 | 
			
		||||
			transition transform .3s ease, opacity .3s ease
 | 
			
		||||
 | 
			
		||||
		&:after
 | 
			
		||||
			content ""
 | 
			
		||||
			display block
 | 
			
		||||
			clear both
 | 
			
		||||
		> div
 | 
			
		||||
			padding 16px
 | 
			
		||||
			overflow-wrap break-word
 | 
			
		||||
			font-size .9em
 | 
			
		||||
			color isDark ? #fff : #4C4C4C
 | 
			
		||||
			border-bottom 1px solid isDark ? rgba(#000, 0.1) : rgba(#000, 0.05)
 | 
			
		||||
 | 
			
		||||
		> .avatar
 | 
			
		||||
			display block
 | 
			
		||||
			float left
 | 
			
		||||
			position -webkit-sticky
 | 
			
		||||
			position sticky
 | 
			
		||||
			top 16px
 | 
			
		||||
			width 42px
 | 
			
		||||
			height 42px
 | 
			
		||||
			border-radius 6px
 | 
			
		||||
			&:after
 | 
			
		||||
				content ""
 | 
			
		||||
				display block
 | 
			
		||||
				clear both
 | 
			
		||||
 | 
			
		||||
		> .body
 | 
			
		||||
			float right
 | 
			
		||||
			width calc(100% - 42px)
 | 
			
		||||
			padding-left 12px
 | 
			
		||||
			> .avatar
 | 
			
		||||
				display block
 | 
			
		||||
				float left
 | 
			
		||||
				position -webkit-sticky
 | 
			
		||||
				position sticky
 | 
			
		||||
				top 16px
 | 
			
		||||
				width 42px
 | 
			
		||||
				height 42px
 | 
			
		||||
				border-radius 6px
 | 
			
		||||
 | 
			
		||||
			> header
 | 
			
		||||
				display flex
 | 
			
		||||
				align-items center
 | 
			
		||||
				margin-bottom 4px
 | 
			
		||||
				white-space nowrap
 | 
			
		||||
			> .body
 | 
			
		||||
				float right
 | 
			
		||||
				width calc(100% - 42px)
 | 
			
		||||
				padding-left 12px
 | 
			
		||||
 | 
			
		||||
				> .name
 | 
			
		||||
					display block
 | 
			
		||||
					margin 0 .5em 0 0
 | 
			
		||||
					padding 0
 | 
			
		||||
					overflow hidden
 | 
			
		||||
					font-weight bold
 | 
			
		||||
					text-overflow ellipsis
 | 
			
		||||
					color isDark ? #fff : #627079
 | 
			
		||||
				> header
 | 
			
		||||
					display flex
 | 
			
		||||
					align-items center
 | 
			
		||||
					margin-bottom 4px
 | 
			
		||||
					white-space nowrap
 | 
			
		||||
 | 
			
		||||
				> .username
 | 
			
		||||
					margin 0 .5em 0 0
 | 
			
		||||
					color isDark ? #606984 : #ccc
 | 
			
		||||
					> .name
 | 
			
		||||
						display block
 | 
			
		||||
						margin 0 .5em 0 0
 | 
			
		||||
						padding 0
 | 
			
		||||
						overflow hidden
 | 
			
		||||
						font-weight bold
 | 
			
		||||
						text-overflow ellipsis
 | 
			
		||||
						color isDark ? #fff : #627079
 | 
			
		||||
 | 
			
		||||
				> .info
 | 
			
		||||
					margin-left auto
 | 
			
		||||
					font-size 0.9em
 | 
			
		||||
					> .username
 | 
			
		||||
						margin 0 .5em 0 0
 | 
			
		||||
						color isDark ? #606984 : #ccc
 | 
			
		||||
 | 
			
		||||
					> .created-at
 | 
			
		||||
						color isDark ? #606984 : #c0c0c0
 | 
			
		||||
					> .info
 | 
			
		||||
						margin-left auto
 | 
			
		||||
						font-size 0.9em
 | 
			
		||||
 | 
			
		||||
			> .text
 | 
			
		||||
				text-align left
 | 
			
		||||
						> .created-at
 | 
			
		||||
							color isDark ? #606984 : #c0c0c0
 | 
			
		||||
 | 
			
		||||
				> .text
 | 
			
		||||
					text-align left
 | 
			
		||||
 | 
			
		||||
.mk-welcome-timeline[data-darkmode]
 | 
			
		||||
	root(true)
 | 
			
		||||
 
 | 
			
		||||
@@ -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(() => {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
 | 
			
		||||
Vue.filter('notePage', note => {
 | 
			
		||||
	return '/notes/' + note.id;
 | 
			
		||||
	return `/notes/${note.id}`;
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -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}` : '')}`;
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
						});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div class="mkw-analog-clock">
 | 
			
		||||
	<mk-widget-container :naked="!(props.design % 2)" :show-header="false">
 | 
			
		||||
	<mk-widget-container :naked="props.style % 2 === 0" :show-header="false">
 | 
			
		||||
		<div class="mkw-analog-clock--body">
 | 
			
		||||
			<mk-analog-clock :dark="$store.state.device.darkmode" :smooth="!(props.design && ~props.design)"/>
 | 
			
		||||
			<mk-analog-clock :dark="$store.state.device.darkmode" :smooth="props.style < 2"/>
 | 
			
		||||
		</div>
 | 
			
		||||
	</mk-widget-container>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -13,13 +13,12 @@ import define from '../../../common/define-widget';
 | 
			
		||||
export default define({
 | 
			
		||||
	name: 'analog-clock',
 | 
			
		||||
	props: () => ({
 | 
			
		||||
		design: -1
 | 
			
		||||
		style: 0
 | 
			
		||||
	})
 | 
			
		||||
}).extend({
 | 
			
		||||
	methods: {
 | 
			
		||||
		func() {
 | 
			
		||||
			if (++this.props.design > 2)
 | 
			
		||||
				this.props.design = -1;
 | 
			
		||||
			this.props.style = (this.props.style + 1) % 4;
 | 
			
		||||
			this.save();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div class="mkw-broadcast"
 | 
			
		||||
	:data-found="broadcasts.length != 0"
 | 
			
		||||
<div class="anltbovirfeutcigvwgmgxipejaeozxi"
 | 
			
		||||
	:data-found="announcements && announcements.length != 0"
 | 
			
		||||
	:data-melt="props.design == 1"
 | 
			
		||||
	:data-mobile="platform == 'mobile'"
 | 
			
		||||
>
 | 
			
		||||
@@ -14,18 +14,17 @@
 | 
			
		||||
		</svg>
 | 
			
		||||
	</div>
 | 
			
		||||
	<p class="fetching" v-if="fetching">%i18n:@fetching%<mk-ellipsis/></p>
 | 
			
		||||
	<h1 v-if="!fetching">{{ broadcasts.length == 0 ? '%i18n:@no-broadcasts%' : broadcasts[i].title }}</h1>
 | 
			
		||||
	<h1 v-if="!fetching">{{ announcements.length == 0 ? '%i18n:@no-broadcasts%' : announcements[i].title }}</h1>
 | 
			
		||||
	<p v-if="!fetching">
 | 
			
		||||
		<span v-if="broadcasts.length != 0" v-html="broadcasts[i].text"></span>
 | 
			
		||||
		<template v-if="broadcasts.length == 0">%i18n:@have-a-nice-day%</template>
 | 
			
		||||
		<span v-if="announcements.length != 0" v-html="announcements[i].text"></span>
 | 
			
		||||
		<template v-if="announcements.length == 0">%i18n:@have-a-nice-day%</template>
 | 
			
		||||
	</p>
 | 
			
		||||
	<a v-if="broadcasts.length > 1" @click="next">%i18n:@next% >></a>
 | 
			
		||||
	<a v-if="announcements.length > 1" @click="next">%i18n:@next% >></a>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import define from '../../../common/define-widget';
 | 
			
		||||
import { lang } from '../../../config';
 | 
			
		||||
 | 
			
		||||
export default define({
 | 
			
		||||
	name: 'broadcast',
 | 
			
		||||
@@ -37,26 +36,18 @@ export default define({
 | 
			
		||||
		return {
 | 
			
		||||
			i: 0,
 | 
			
		||||
			fetching: true,
 | 
			
		||||
			broadcasts: []
 | 
			
		||||
			announcements: []
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	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.announcements = meta.broadcasts;
 | 
			
		||||
			this.fetching = false;
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		next() {
 | 
			
		||||
			if (this.i == this.broadcasts.length - 1) {
 | 
			
		||||
			if (this.i == this.announcements.length - 1) {
 | 
			
		||||
				this.i = 0;
 | 
			
		||||
			} else {
 | 
			
		||||
				this.i++;
 | 
			
		||||
@@ -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
 | 
			
		||||
@@ -135,22 +126,18 @@ export default define({
 | 
			
		||||
		margin 0
 | 
			
		||||
		font-size 0.95em
 | 
			
		||||
		font-weight normal
 | 
			
		||||
		color #4078c0
 | 
			
		||||
		color isDark ? #539eff : #4078c0
 | 
			
		||||
 | 
			
		||||
	> p
 | 
			
		||||
		display block
 | 
			
		||||
		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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -163,7 +163,7 @@ export default Vue.extend({
 | 
			
		||||
							});
 | 
			
		||||
							break;
 | 
			
		||||
						default:
 | 
			
		||||
							alert('%i18n:@unhandled-error% ' + err);
 | 
			
		||||
							alert(`%i18n:@unhandled-error% ${err}`);
 | 
			
		||||
					}
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
@@ -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');
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
						});
 | 
			
		||||
 
 | 
			
		||||
@@ -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}")`;
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -42,8 +42,8 @@
 | 
			
		||||
				<span v-if="p.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span>
 | 
			
		||||
				<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i"/>
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="media" v-if="p.media.length > 0">
 | 
			
		||||
				<mk-media-list :media-list="p.media" :raw="true"/>
 | 
			
		||||
			<div class="files" v-if="p.files.length > 0">
 | 
			
		||||
				<mk-media-list :media-list="p.files" :raw="true"/>
 | 
			
		||||
			</div>
 | 
			
		||||
			<mk-poll v-if="p.poll" :note="p"/>
 | 
			
		||||
			<mk-url-preview v-for="url in urls" :url="url" :key="url" :detail="true"/>
 | 
			
		||||
@@ -86,6 +86,7 @@ import MkRenoteFormWindow from './renote-form-window.vue';
 | 
			
		||||
import MkNoteMenu from '../../../common/views/components/note-menu.vue';
 | 
			
		||||
import MkReactionPicker from '../../../common/views/components/reaction-picker.vue';
 | 
			
		||||
import XSub from './notes.note.sub.vue';
 | 
			
		||||
import { sum } from '../../../../../prelude/array';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	components: {
 | 
			
		||||
@@ -114,7 +115,7 @@ export default Vue.extend({
 | 
			
		||||
		isRenote(): boolean {
 | 
			
		||||
			return (this.note.renote &&
 | 
			
		||||
				this.note.text == null &&
 | 
			
		||||
				this.note.mediaIds.length == 0 &&
 | 
			
		||||
				this.note.fileIds.length == 0 &&
 | 
			
		||||
				this.note.poll == null);
 | 
			
		||||
		},
 | 
			
		||||
		p(): any {
 | 
			
		||||
@@ -122,9 +123,7 @@ export default Vue.extend({
 | 
			
		||||
		},
 | 
			
		||||
		reactionsCount(): number {
 | 
			
		||||
			return this.p.reactionCounts
 | 
			
		||||
				? Object.keys(this.p.reactionCounts)
 | 
			
		||||
					.map(key => this.p.reactionCounts[key])
 | 
			
		||||
					.reduce((a, b) => a + b)
 | 
			
		||||
				? sum(Object.values(this.p.reactionCounts))
 | 
			
		||||
				: 0;
 | 
			
		||||
		},
 | 
			
		||||
		title(): string {
 | 
			
		||||
 
 | 
			
		||||
@@ -28,8 +28,8 @@
 | 
			
		||||
						<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i" :class="$style.text"/>
 | 
			
		||||
						<a class="rp" v-if="p.renote">RP:</a>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="media" v-if="p.media.length > 0">
 | 
			
		||||
						<mk-media-list :media-list="p.media"/>
 | 
			
		||||
					<div class="files" v-if="p.files.length > 0">
 | 
			
		||||
						<mk-media-list :media-list="p.files"/>
 | 
			
		||||
					</div>
 | 
			
		||||
					<mk-poll v-if="p.poll" :note="p" ref="pollViewer"/>
 | 
			
		||||
					<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% 位置情報</a>
 | 
			
		||||
@@ -78,6 +78,7 @@ import MkRenoteFormWindow from './renote-form-window.vue';
 | 
			
		||||
import MkNoteMenu from '../../../common/views/components/note-menu.vue';
 | 
			
		||||
import MkReactionPicker from '../../../common/views/components/reaction-picker.vue';
 | 
			
		||||
import XSub from './notes.note.sub.vue';
 | 
			
		||||
import { sum } from '../../../../../prelude/array';
 | 
			
		||||
 | 
			
		||||
function focus(el, fn) {
 | 
			
		||||
	const target = fn(el);
 | 
			
		||||
@@ -110,7 +111,7 @@ export default Vue.extend({
 | 
			
		||||
		isRenote(): boolean {
 | 
			
		||||
			return (this.note.renote &&
 | 
			
		||||
				this.note.text == null &&
 | 
			
		||||
				this.note.mediaIds.length == 0 &&
 | 
			
		||||
				this.note.fileIds.length == 0 &&
 | 
			
		||||
				this.note.poll == null);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
@@ -120,9 +121,7 @@ export default Vue.extend({
 | 
			
		||||
 | 
			
		||||
		reactionsCount(): number {
 | 
			
		||||
			return this.p.reactionCounts
 | 
			
		||||
				? Object.keys(this.p.reactionCounts)
 | 
			
		||||
					.map(key => this.p.reactionCounts[key])
 | 
			
		||||
					.reduce((a, b) => a + b)
 | 
			
		||||
				? sum(Object.values(this.p.reactionCounts))
 | 
			
		||||
				: 0;
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -122,7 +122,7 @@ export default Vue.extend({
 | 
			
		||||
		prepend(note, silent = false) {
 | 
			
		||||
			//#region 弾く
 | 
			
		||||
			const isMyNote = note.userId == this.$store.state.i.id;
 | 
			
		||||
			const isPureRenote = note.renoteId != null && note.text == null && note.mediaIds.length == 0 && note.poll == null;
 | 
			
		||||
			const isPureRenote = note.renoteId != null && note.text == null && note.fileIds.length == 0 && note.poll == null;
 | 
			
		||||
 | 
			
		||||
			if (this.$store.state.settings.showMyRenotes === false) {
 | 
			
		||||
				if (isMyNote && isPureRenote) {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
		<span class="icon" v-if="geo">%fa:map-marker-alt%</span>
 | 
			
		||||
		<span v-if="!reply">%i18n:@note%</span>
 | 
			
		||||
		<span v-if="reply">%i18n:@reply%</span>
 | 
			
		||||
		<span class="count" v-if="media.length != 0">{{ '%i18n:@attaches%'.replace('{}', media.length) }}</span>
 | 
			
		||||
		<span class="count" v-if="files.length != 0">{{ '%i18n:@attaches%'.replace('{}', files.length) }}</span>
 | 
			
		||||
		<span class="count" v-if="uploadings.length != 0">{{ '%i18n:@uploading-media%'.replace('{}', uploadings.length) }}<mk-ellipsis/></span>
 | 
			
		||||
	</span>
 | 
			
		||||
 | 
			
		||||
@@ -14,7 +14,7 @@
 | 
			
		||||
			:reply="reply"
 | 
			
		||||
			@posted="onPosted"
 | 
			
		||||
			@change-uploadings="onChangeUploadings"
 | 
			
		||||
			@change-attached-media="onChangeMedia"
 | 
			
		||||
			@change-attached-files="onChangeFiles"
 | 
			
		||||
			@geo-attached="onGeoAttached"
 | 
			
		||||
			@geo-dettached="onGeoDettached"/>
 | 
			
		||||
	</div>
 | 
			
		||||
@@ -29,7 +29,7 @@ export default Vue.extend({
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			uploadings: [],
 | 
			
		||||
			media: [],
 | 
			
		||||
			files: [],
 | 
			
		||||
			geo: null
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
@@ -42,8 +42,8 @@ export default Vue.extend({
 | 
			
		||||
		onChangeUploadings(files) {
 | 
			
		||||
			this.uploadings = files;
 | 
			
		||||
		},
 | 
			
		||||
		onChangeMedia(media) {
 | 
			
		||||
			this.media = media;
 | 
			
		||||
		onChangeFiles(files) {
 | 
			
		||||
			this.files = files;
 | 
			
		||||
		},
 | 
			
		||||
		onGeoAttached(geo) {
 | 
			
		||||
			this.geo = geo;
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@
 | 
			
		||||
			@keydown="onKeydown" @paste="onPaste" :placeholder="placeholder"
 | 
			
		||||
			v-autocomplete="'text'"
 | 
			
		||||
		></textarea>
 | 
			
		||||
		<div class="medias" :class="{ with: poll }" v-show="files.length != 0">
 | 
			
		||||
		<div class="files" :class="{ with: poll }" v-show="files.length != 0">
 | 
			
		||||
			<x-draggable :list="files" :options="{ animation: 150 }">
 | 
			
		||||
				<div v-for="file in files" :key="file.id">
 | 
			
		||||
					<div class="img" :style="{ backgroundImage: `url(${file.thumbnailUrl})` }" :title="file.name"></div>
 | 
			
		||||
@@ -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">
 | 
			
		||||
@@ -62,6 +62,7 @@ import getFace from '../../../common/scripts/get-face';
 | 
			
		||||
import MkVisibilityChooser from '../../../common/views/components/visibility-chooser.vue';
 | 
			
		||||
import parse from '../../../../../mfm/parse';
 | 
			
		||||
import { host } from '../../../config';
 | 
			
		||||
import { erase } from '../../../../../prelude/array';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	components: {
 | 
			
		||||
@@ -99,7 +100,7 @@ export default Vue.extend({
 | 
			
		||||
			useCw: false,
 | 
			
		||||
			cw: null,
 | 
			
		||||
			geo: null,
 | 
			
		||||
			visibility: this.$store.state.device.visibility || 'public',
 | 
			
		||||
			visibility: this.$store.state.settings.rememberNoteVisibility ? (this.$store.state.device.visibility || this.$store.state.settings.defaultNoteVisibility) : this.$store.state.settings.defaultNoteVisibility,
 | 
			
		||||
			visibleUsers: [],
 | 
			
		||||
			autocomplete: null,
 | 
			
		||||
			draghover: false,
 | 
			
		||||
@@ -110,9 +111,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';
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
@@ -188,7 +189,7 @@ export default Vue.extend({
 | 
			
		||||
							(this.$refs.poll as any).set(draft.data.poll);
 | 
			
		||||
						});
 | 
			
		||||
					}
 | 
			
		||||
					this.$emit('change-attached-media', this.files);
 | 
			
		||||
					this.$emit('change-attached-files', this.files);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
@@ -225,12 +226,12 @@ export default Vue.extend({
 | 
			
		||||
 | 
			
		||||
		attachMedia(driveFile) {
 | 
			
		||||
			this.files.push(driveFile);
 | 
			
		||||
			this.$emit('change-attached-media', this.files);
 | 
			
		||||
			this.$emit('change-attached-files', this.files);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		detachMedia(id) {
 | 
			
		||||
			this.files = this.files.filter(x => x.id != id);
 | 
			
		||||
			this.$emit('change-attached-media', this.files);
 | 
			
		||||
			this.$emit('change-attached-files', this.files);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		onChangeFile() {
 | 
			
		||||
@@ -249,7 +250,7 @@ export default Vue.extend({
 | 
			
		||||
			this.text = '';
 | 
			
		||||
			this.files = [];
 | 
			
		||||
			this.poll = false;
 | 
			
		||||
			this.$emit('change-attached-media', this.files);
 | 
			
		||||
			this.$emit('change-attached-files', this.files);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		onKeydown(e) {
 | 
			
		||||
@@ -297,7 +298,7 @@ export default Vue.extend({
 | 
			
		||||
			if (driveFile != null && driveFile != '') {
 | 
			
		||||
				const file = JSON.parse(driveFile);
 | 
			
		||||
				this.files.push(file);
 | 
			
		||||
				this.$emit('change-attached-media', this.files);
 | 
			
		||||
				this.$emit('change-attached-files', this.files);
 | 
			
		||||
				e.preventDefault();
 | 
			
		||||
			}
 | 
			
		||||
			//#endregion
 | 
			
		||||
@@ -313,7 +314,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
 | 
			
		||||
				});
 | 
			
		||||
@@ -346,7 +347,7 @@ export default Vue.extend({
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		removeVisibleUser(user) {
 | 
			
		||||
			this.visibleUsers = this.visibleUsers.filter(u => u != user);
 | 
			
		||||
			this.visibleUsers = erase(user, this.visibleUsers);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		post() {
 | 
			
		||||
@@ -354,7 +355,7 @@ export default Vue.extend({
 | 
			
		||||
 | 
			
		||||
			(this as any).api('notes/create', {
 | 
			
		||||
				text: this.text == '' ? undefined : this.text,
 | 
			
		||||
				mediaIds: this.files.length > 0 ? this.files.map(f => f.id) : undefined,
 | 
			
		||||
				fileIds: this.files.length > 0 ? this.files.map(f => f.id) : undefined,
 | 
			
		||||
				replyId: this.reply ? this.reply.id : undefined,
 | 
			
		||||
				renoteId: this.renote ? this.renote.id : undefined,
 | 
			
		||||
				poll: this.poll ? (this.$refs.poll as any).get() : undefined,
 | 
			
		||||
@@ -514,7 +515,7 @@ root(isDark)
 | 
			
		||||
				margin-right 8px
 | 
			
		||||
				white-space nowrap
 | 
			
		||||
 | 
			
		||||
		> .medias
 | 
			
		||||
		> .files
 | 
			
		||||
			margin 0
 | 
			
		||||
			padding 0
 | 
			
		||||
			background isDark ? #181b23 : lighten($theme-color, 98%)
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,22 @@
 | 
			
		||||
			<mk-switch v-model="autoPopout" text="%i18n:@auto-popout%">
 | 
			
		||||
				<span>%i18n:@auto-popout-desc%</span>
 | 
			
		||||
			</mk-switch>
 | 
			
		||||
 | 
			
		||||
			<section>
 | 
			
		||||
				<header>%i18n:@note-visibility%</header>
 | 
			
		||||
				<mk-switch v-model="$store.state.settings.rememberNoteVisibility" @change="onChangeRememberNoteVisibility" text="%i18n:@remember-note-visibility%"/>
 | 
			
		||||
				<section>
 | 
			
		||||
					<header>%i18n:@default-note-visibility%</header>
 | 
			
		||||
					<ui-select v-model="defaultNoteVisibility">
 | 
			
		||||
						<option value="public">%i18n:common.note-visibility.public%</option>
 | 
			
		||||
						<option value="home">%i18n:common.note-visibility.home%</option>
 | 
			
		||||
						<option value="followers">%i18n:common.note-visibility.followers%</option>
 | 
			
		||||
						<option value="specified">%i18n:common.note-visibility.specified%</option>
 | 
			
		||||
						<option value="private">%i18n:common.note-visibility.private%</option>
 | 
			
		||||
					</ui-select>
 | 
			
		||||
				</section>
 | 
			
		||||
			</section>
 | 
			
		||||
 | 
			
		||||
			<details>
 | 
			
		||||
				<summary>%i18n:@advanced%</summary>
 | 
			
		||||
				<mk-switch v-model="apiViaStream" text="%i18n:@api-via-stream%">
 | 
			
		||||
@@ -44,6 +60,7 @@
 | 
			
		||||
				<button class="ui" @click="deleteWallpaper">%i18n:@delete-wallpaper%</button>
 | 
			
		||||
				<mk-switch v-model="darkmode" text="%i18n:@dark-mode%"/>
 | 
			
		||||
				<mk-switch v-model="$store.state.settings.circleIcons" @change="onChangeCircleIcons" text="%i18n:@circle-icons%"/>
 | 
			
		||||
				<mk-switch v-model="$store.state.settings.contrastedAcct" @change="onChangeContrastedAcct" text="%i18n:@contrasted-acct%"/>
 | 
			
		||||
				<mk-switch v-model="$store.state.settings.gradientWindowHeader" @change="onChangeGradientWindowHeader" text="%i18n:@gradient-window-header%"/>
 | 
			
		||||
				<mk-switch v-model="$store.state.settings.iLikeSushi" @change="onChangeILikeSushi" text="%i18n:common.i-like-sushi%"/>
 | 
			
		||||
			</div>
 | 
			
		||||
@@ -238,6 +255,11 @@ export default Vue.extend({
 | 
			
		||||
			set(value) { this.$store.commit('device/set', { key: 'apiViaStream', value }); }
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		defaultNoteVisibility: {
 | 
			
		||||
			get() { return this.$store.state.settings.defaultNoteVisibility; },
 | 
			
		||||
			set(value) { this.$store.commit('settings/set', { key: 'defaultNoteVisibility', value }); }
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		autoPopout: {
 | 
			
		||||
			get() { return this.$store.state.device.autoPopout; },
 | 
			
		||||
			set(value) { this.$store.commit('device/set', { key: 'autoPopout', value }); }
 | 
			
		||||
@@ -311,6 +333,12 @@ export default Vue.extend({
 | 
			
		||||
				value: v
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		onChangeRememberNoteVisibility(v) {
 | 
			
		||||
			this.$store.dispatch('settings/set', {
 | 
			
		||||
				key: 'rememberNoteVisibility',
 | 
			
		||||
				value: v
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		onChangeAutoWatch(v) {
 | 
			
		||||
			(this as any).api('i/update', {
 | 
			
		||||
				autoWatch: v
 | 
			
		||||
@@ -376,6 +404,12 @@ export default Vue.extend({
 | 
			
		||||
				value: v
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		onChangeContrastedAcct(v) {
 | 
			
		||||
			this.$store.dispatch('settings/set', {
 | 
			
		||||
				key: 'contrastedAcct',
 | 
			
		||||
				value: v
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		onChangeILikeSushi(v) {
 | 
			
		||||
			this.$store.dispatch('settings/set', {
 | 
			
		||||
				key: 'iLikeSushi',
 | 
			
		||||
 
 | 
			
		||||
@@ -7,9 +7,9 @@
 | 
			
		||||
		<misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i"/>
 | 
			
		||||
		<a class="rp" v-if="note.renoteId" :href="`/notes/${note.renoteId}`">RP: ...</a>
 | 
			
		||||
	</div>
 | 
			
		||||
	<details v-if="note.media.length > 0">
 | 
			
		||||
		<summary>({{ '%i18n:@media-count%'.replace('{}', note.media.length) }})</summary>
 | 
			
		||||
		<mk-media-list :media-list="note.media"/>
 | 
			
		||||
	<details v-if="note.files.length > 0">
 | 
			
		||||
		<summary>({{ '%i18n:@media-count%'.replace('{}', note.files.length) }})</summary>
 | 
			
		||||
		<mk-media-list :media-list="note.files"/>
 | 
			
		||||
	</details>
 | 
			
		||||
	<details v-if="note.poll">
 | 
			
		||||
		<summary>%i18n:@poll%</summary>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
							
								
								
									
										41
									
								
								src/client/app/desktop/views/pages/admin/admin.hashtags.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/client/app/desktop/views/pages/admin/admin.hashtags.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div class="jdnqwkzlnxcfftthoybjxrebyolvoucw mk-admin-card">
 | 
			
		||||
	<header>%i18n:@hided-tags%</header>
 | 
			
		||||
	<textarea v-model="hidedTags"></textarea>
 | 
			
		||||
	<button class="ui" @click="save">%i18n:@save%</button>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from "vue";
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			hidedTags: '',
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	created() {
 | 
			
		||||
		(this as any).os.getMeta().then(meta => {
 | 
			
		||||
			this.hidedTags = meta.hidedTags.join('\n');
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		save() {
 | 
			
		||||
			(this as any).api('admin/update-meta', {
 | 
			
		||||
				hidedTags: this.hidedTags.split('\n')
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
@import '~const.styl'
 | 
			
		||||
 | 
			
		||||
.jdnqwkzlnxcfftthoybjxrebyolvoucw
 | 
			
		||||
	textarea
 | 
			
		||||
		width 100%
 | 
			
		||||
		min-height 300px
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
@@ -4,6 +4,9 @@
 | 
			
		||||
		<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('hashtags')" :class="{ active: page == 'hashtags' }">%fa:hashtag .fw%%i18n:@hashtags%</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 +16,12 @@
 | 
			
		||||
			<x-dashboard/>
 | 
			
		||||
			<x-charts/>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div v-show="page == 'announcements'">
 | 
			
		||||
			<x-announcements/>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div v-show="page == 'hashtags'">
 | 
			
		||||
			<x-hashtags/>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div v-if="page == 'users'">
 | 
			
		||||
			<x-suspend-user/>
 | 
			
		||||
			<x-unsuspend-user/>
 | 
			
		||||
@@ -28,6 +37,8 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from "vue";
 | 
			
		||||
import XDashboard from "./admin.dashboard.vue";
 | 
			
		||||
import XAnnouncements from "./admin.announcements.vue";
 | 
			
		||||
import XHashtags from "./admin.hashtags.vue";
 | 
			
		||||
import XSuspendUser from "./admin.suspend-user.vue";
 | 
			
		||||
import XUnsuspendUser from "./admin.unsuspend-user.vue";
 | 
			
		||||
import XVerifyUser from "./admin.verify-user.vue";
 | 
			
		||||
@@ -37,6 +48,8 @@ import XCharts from "../../components/charts.vue";
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	components: {
 | 
			
		||||
		XDashboard,
 | 
			
		||||
		XAnnouncements,
 | 
			
		||||
		XHashtags,
 | 
			
		||||
		XSuspendUser,
 | 
			
		||||
		XUnsuspendUser,
 | 
			
		||||
		XVerifyUser,
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,7 @@
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import Menu from '../../../../common/views/components/menu.vue';
 | 
			
		||||
import contextmenu from '../../../api/contextmenu';
 | 
			
		||||
import { countIf } from '../../../../../../prelude/array';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	props: {
 | 
			
		||||
@@ -117,7 +118,7 @@ export default Vue.extend({
 | 
			
		||||
		toggleActive() {
 | 
			
		||||
			if (!this.isStacked) return;
 | 
			
		||||
			const vms = this.$store.state.settings.deck.layout.find(ids => ids.indexOf(this.column.id) != -1).map(id => this.getColumnVm(id));
 | 
			
		||||
			if (this.active && vms.filter(vm => vm.$el.classList.contains('active')).length == 1) return;
 | 
			
		||||
			if (this.active && countIf(vm => vm.$el.classList.contains('active'), vms) == 1) return;
 | 
			
		||||
			this.active = !this.active;
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -68,7 +68,7 @@ export default Vue.extend({
 | 
			
		||||
				(this as any).api('notes/user-list-timeline', {
 | 
			
		||||
					listId: this.list.id,
 | 
			
		||||
					limit: fetchLimit + 1,
 | 
			
		||||
					mediaOnly: this.mediaOnly,
 | 
			
		||||
					withFiles: this.mediaOnly,
 | 
			
		||||
					includeMyRenotes: this.$store.state.settings.showMyRenotes,
 | 
			
		||||
					includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes,
 | 
			
		||||
					includeLocalRenotes: this.$store.state.settings.showLocalRenotes
 | 
			
		||||
@@ -90,7 +90,7 @@ export default Vue.extend({
 | 
			
		||||
				listId: this.list.id,
 | 
			
		||||
				limit: fetchLimit + 1,
 | 
			
		||||
				untilId: (this.$refs.timeline as any).tail().id,
 | 
			
		||||
				mediaOnly: this.mediaOnly,
 | 
			
		||||
				withFiles: this.mediaOnly,
 | 
			
		||||
				includeMyRenotes: this.$store.state.settings.showMyRenotes,
 | 
			
		||||
				includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes,
 | 
			
		||||
				includeLocalRenotes: this.$store.state.settings.showLocalRenotes
 | 
			
		||||
@@ -109,7 +109,7 @@ export default Vue.extend({
 | 
			
		||||
			return promise;
 | 
			
		||||
		},
 | 
			
		||||
		onNote(note) {
 | 
			
		||||
			if (this.mediaOnly && note.media.length == 0) return;
 | 
			
		||||
			if (this.mediaOnly && note.files.length == 0) return;
 | 
			
		||||
 | 
			
		||||
			// Prepend a note
 | 
			
		||||
			(this.$refs.timeline as any).prepend(note);
 | 
			
		||||
 
 | 
			
		||||
@@ -28,8 +28,8 @@
 | 
			
		||||
						<misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i"/>
 | 
			
		||||
						<a class="rp" v-if="p.renote != null">RP:</a>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="media" v-if="p.media.length > 0">
 | 
			
		||||
						<mk-media-list :media-list="p.media"/>
 | 
			
		||||
					<div class="files" v-if="p.files.length > 0">
 | 
			
		||||
						<mk-media-list :media-list="p.files"/>
 | 
			
		||||
					</div>
 | 
			
		||||
					<mk-poll v-if="p.poll" :note="p" ref="pollViewer"/>
 | 
			
		||||
					<a class="location" v-if="p.geo" :href="`https://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a>
 | 
			
		||||
@@ -54,11 +54,11 @@
 | 
			
		||||
	</article>
 | 
			
		||||
</div>
 | 
			
		||||
<div v-else class="srwrkujossgfuhrbnvqkybtzxpblgchi">
 | 
			
		||||
	<div v-if="note.media.length > 0">
 | 
			
		||||
		<mk-media-list :media-list="note.media"/>
 | 
			
		||||
	<div v-if="note.files.length > 0">
 | 
			
		||||
		<mk-media-list :media-list="note.files"/>
 | 
			
		||||
	</div>
 | 
			
		||||
	<div v-if="note.renote && note.renote.media.length > 0">
 | 
			
		||||
		<mk-media-list :media-list="note.renote.media"/>
 | 
			
		||||
	<div v-if="note.renote && note.renote.files.length > 0">
 | 
			
		||||
		<mk-media-list :media-list="note.renote.files"/>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
@@ -100,7 +100,7 @@ export default Vue.extend({
 | 
			
		||||
		isRenote(): boolean {
 | 
			
		||||
			return (this.note.renote &&
 | 
			
		||||
				this.note.text == null &&
 | 
			
		||||
				this.note.mediaIds.length == 0 &&
 | 
			
		||||
				this.note.fileIds.length == 0 &&
 | 
			
		||||
				this.note.poll == null);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
@@ -371,7 +371,7 @@ root(isDark)
 | 
			
		||||
					.mk-url-preview
 | 
			
		||||
						margin-top 8px
 | 
			
		||||
 | 
			
		||||
					> .media
 | 
			
		||||
					> .files
 | 
			
		||||
						> img
 | 
			
		||||
							display block
 | 
			
		||||
							max-width 100%
 | 
			
		||||
 
 | 
			
		||||
@@ -127,7 +127,7 @@ export default Vue.extend({
 | 
			
		||||
		prepend(note, silent = false) {
 | 
			
		||||
			//#region 弾く
 | 
			
		||||
			const isMyNote = note.userId == this.$store.state.i.id;
 | 
			
		||||
			const isPureRenote = note.renoteId != null && note.text == null && note.mediaIds.length == 0 && note.poll == null;
 | 
			
		||||
			const isPureRenote = note.renoteId != null && note.text == null && note.fileIds.length == 0 && note.poll == null;
 | 
			
		||||
 | 
			
		||||
			if (this.$store.state.settings.showMyRenotes === false) {
 | 
			
		||||
				if (isMyNote && isPureRenote) {
 | 
			
		||||
 
 | 
			
		||||
@@ -96,7 +96,7 @@ export default Vue.extend({
 | 
			
		||||
			(this.$refs.timeline as any).init(() => new Promise((res, rej) => {
 | 
			
		||||
				(this as any).api(this.endpoint, {
 | 
			
		||||
					limit: fetchLimit + 1,
 | 
			
		||||
					mediaOnly: this.mediaOnly,
 | 
			
		||||
					withFiles: this.mediaOnly,
 | 
			
		||||
					includeMyRenotes: this.$store.state.settings.showMyRenotes,
 | 
			
		||||
					includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes,
 | 
			
		||||
					includeLocalRenotes: this.$store.state.settings.showLocalRenotes
 | 
			
		||||
@@ -117,7 +117,7 @@ export default Vue.extend({
 | 
			
		||||
 | 
			
		||||
			const promise = (this as any).api(this.endpoint, {
 | 
			
		||||
				limit: fetchLimit + 1,
 | 
			
		||||
				mediaOnly: this.mediaOnly,
 | 
			
		||||
				withFiles: this.mediaOnly,
 | 
			
		||||
				untilId: (this.$refs.timeline as any).tail().id,
 | 
			
		||||
				includeMyRenotes: this.$store.state.settings.showMyRenotes,
 | 
			
		||||
				includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes,
 | 
			
		||||
@@ -138,7 +138,7 @@ export default Vue.extend({
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		onNote(note) {
 | 
			
		||||
			if (this.mediaOnly && note.media.length == 0) return;
 | 
			
		||||
			if (this.mediaOnly && note.files.length == 0) return;
 | 
			
		||||
 | 
			
		||||
			// Prepend a note
 | 
			
		||||
			(this.$refs.timeline as any).prepend(note);
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -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}`);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
			});
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@
 | 
			
		||||
		<div class="title">
 | 
			
		||||
			<p class="name">{{ user | userName }}</p>
 | 
			
		||||
			<div>
 | 
			
		||||
				<span class="username"><mk-acct :user="user"/></span>
 | 
			
		||||
				<span class="username"><mk-acct :user="user" :detail="true" /></span>
 | 
			
		||||
				<span v-if="user.isBot" title="%i18n:@is-bot%">%fa:robot%</span>
 | 
			
		||||
				<span class="location" v-if="user.host === null && user.profile.location">%fa:map-marker% {{ user.profile.location }}</span>
 | 
			
		||||
				<span class="birthday" v-if="user.host === null && user.profile.birthday">%fa:birthday-cake% {{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳)</span>
 | 
			
		||||
 
 | 
			
		||||
@@ -24,12 +24,12 @@ export default Vue.extend({
 | 
			
		||||
	mounted() {
 | 
			
		||||
		(this as any).api('users/notes', {
 | 
			
		||||
			userId: this.user.id,
 | 
			
		||||
			withMedia: true,
 | 
			
		||||
			withFiles: true,
 | 
			
		||||
			limit: 9
 | 
			
		||||
		}).then(notes => {
 | 
			
		||||
			notes.forEach(note => {
 | 
			
		||||
				note.media.forEach(media => {
 | 
			
		||||
					if (this.images.length < 9) this.images.push(media);
 | 
			
		||||
				note.files.forEach(file => {
 | 
			
		||||
					if (this.images.length < 9) this.images.push(file);
 | 
			
		||||
				});
 | 
			
		||||
			});
 | 
			
		||||
			this.fetching = false;
 | 
			
		||||
 
 | 
			
		||||
@@ -66,7 +66,7 @@ export default Vue.extend({
 | 
			
		||||
					limit: fetchLimit + 1,
 | 
			
		||||
					untilDate: this.date ? this.date.getTime() : undefined,
 | 
			
		||||
					includeReplies: this.mode == 'with-replies',
 | 
			
		||||
					withMedia: this.mode == 'with-media'
 | 
			
		||||
					withFiles: this.mode == 'with-media'
 | 
			
		||||
				}).then(notes => {
 | 
			
		||||
					if (notes.length == fetchLimit + 1) {
 | 
			
		||||
						notes.pop();
 | 
			
		||||
@@ -86,7 +86,7 @@ export default Vue.extend({
 | 
			
		||||
				userId: this.user.id,
 | 
			
		||||
				limit: fetchLimit + 1,
 | 
			
		||||
				includeReplies: this.mode == 'with-replies',
 | 
			
		||||
				withMedia: this.mode == 'with-media',
 | 
			
		||||
				withFiles: this.mode == 'with-media',
 | 
			
		||||
				untilId: (this.$refs.timeline as any).tail().id
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,45 +1,143 @@
 | 
			
		||||
<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>
 | 
			
		||||
	<div class="body">
 | 
			
		||||
		<div class="container">
 | 
			
		||||
			<div class="info">
 | 
			
		||||
				<span><b>{{ host }}</b></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">
 | 
			
		||||
 | 
			
		||||
	<mk-forkit class="forkit"/>
 | 
			
		||||
 | 
			
		||||
	<main>
 | 
			
		||||
		<div class="body">
 | 
			
		||||
			<div class="main block">
 | 
			
		||||
				<div>
 | 
			
		||||
					<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>
 | 
			
		||||
 | 
			
		||||
					<div class="info">
 | 
			
		||||
						<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>
 | 
			
		||||
 | 
			
		||||
					<p class="desc" v-html="description || '%i18n:common.about%'"></p>
 | 
			
		||||
					<a ref="signup" @click="signup">📦 %i18n:@signup%</a>
 | 
			
		||||
					<a class="about" @click="about">%i18n:@about%</a>
 | 
			
		||||
 | 
			
		||||
					<p class="sign">
 | 
			
		||||
						<span class="signup" @click="signup">%i18n:@signup%</span>
 | 
			
		||||
						<span class="divider">|</span>
 | 
			
		||||
						<span class="signin" @click="signin">%i18n:@signin%</span>
 | 
			
		||||
					</p>
 | 
			
		||||
 | 
			
		||||
					<img src="/assets/pointer.png" alt="" class="char">
 | 
			
		||||
				</div>
 | 
			
		||||
			</div>
 | 
			
		||||
 | 
			
		||||
			<div class="announcements block">
 | 
			
		||||
				<header>%fa:broadcast-tower% %i18n:@announcements%</header>
 | 
			
		||||
				<div v-if="announcements && announcements.length > 0">
 | 
			
		||||
					<div v-for="announcement in announcements">
 | 
			
		||||
						<h1 v-html="announcement.title"></h1>
 | 
			
		||||
						<div v-html="announcement.text"></div>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
			</div>
 | 
			
		||||
 | 
			
		||||
			<div class="photos block">
 | 
			
		||||
				<header>%fa:images% %i18n:@photos%</header>
 | 
			
		||||
				<div>
 | 
			
		||||
					<div v-for="photo in photos" :style="`background-image: url(${photo.thumbnailUrl})`"></div>
 | 
			
		||||
				</div>
 | 
			
		||||
			</div>
 | 
			
		||||
 | 
			
		||||
			<div class="tag-cloud block">
 | 
			
		||||
				<div>
 | 
			
		||||
					<mk-tag-cloud/>
 | 
			
		||||
				</div>
 | 
			
		||||
			</div>
 | 
			
		||||
 | 
			
		||||
			<div class="nav block">
 | 
			
		||||
				<div>
 | 
			
		||||
					<mk-nav class="nav"/>
 | 
			
		||||
				</div>
 | 
			
		||||
			</div>
 | 
			
		||||
 | 
			
		||||
			<div class="side">
 | 
			
		||||
				<div class="trends block">
 | 
			
		||||
					<div>
 | 
			
		||||
						<mk-trends/>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
 | 
			
		||||
				<div class="tl block">
 | 
			
		||||
					<header>%fa:comment-alt R% %i18n:@timeline%</header>
 | 
			
		||||
					<div>
 | 
			
		||||
						<mk-welcome-timeline class="tl" :max="20"/>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
 | 
			
		||||
				<div class="info block">
 | 
			
		||||
					<header>%fa:info-circle% %i18n:@info%</header>
 | 
			
		||||
					<div>
 | 
			
		||||
						<div v-if="meta" class="body">
 | 
			
		||||
							<p>Version: <b>{{ meta.version }}</b></p>
 | 
			
		||||
							<p>Maintainer: <b><a :href="meta.maintainer.url" target="_blank">{{ meta.maintainer.name }}</a></b></p>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
				</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>
 | 
			
		||||
			</div>
 | 
			
		||||
			<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>
 | 
			
		||||
	<modal name="signup" width="500px" height="auto" scrollable>
 | 
			
		||||
		<header :class="$style.signupFormHeader">%i18n:@signup%</header>
 | 
			
		||||
		<mk-signup :class="$style.signupForm"/>
 | 
			
		||||
	</main>
 | 
			
		||||
 | 
			
		||||
	<modal name="about" :class="$store.state.device.darkmode ? ['about', 'modal-dark'] : ['about', 'modal-light']" width="800px" height="auto" scrollable>
 | 
			
		||||
		<article class="fpdezooorhntlzyeszemrsqdlgbysvxq">
 | 
			
		||||
			<h1>%i18n:common.intro.title%</h1>
 | 
			
		||||
			<p v-html="'%i18n:common.intro.about%'"></p>
 | 
			
		||||
			<section>
 | 
			
		||||
				<h2>%i18n:common.intro.features%</h2>
 | 
			
		||||
				<section>
 | 
			
		||||
					<div class="body">
 | 
			
		||||
						<h3>%i18n:common.intro.rich-contents%</h3>
 | 
			
		||||
						<p v-html="'%i18n:common.intro.rich-contents-desc%'"></p>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="image"><img src="/assets/about/post.png" alt=""></div>
 | 
			
		||||
				</section>
 | 
			
		||||
				<section>
 | 
			
		||||
					<div class="body">
 | 
			
		||||
						<h3>%i18n:common.intro.reaction%</h3>
 | 
			
		||||
						<p v-html="'%i18n:common.intro.reaction-desc%'"></p>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="image"><img src="/assets/about/reaction.png" alt=""></div>
 | 
			
		||||
				</section>
 | 
			
		||||
				<section>
 | 
			
		||||
					<div class="body">
 | 
			
		||||
						<h3>%i18n:common.intro.ui%</h3>
 | 
			
		||||
						<p v-html="'%i18n:common.intro.ui-desc%'"></p>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="image"><img src="/assets/about/ui.png" alt=""></div>
 | 
			
		||||
				</section>
 | 
			
		||||
				<section>
 | 
			
		||||
					<div class="body">
 | 
			
		||||
						<h3>%i18n:common.intro.drive%</h3>
 | 
			
		||||
						<p v-html="'%i18n:common.intro.drive-desc%'"></p>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="image"><img src="/assets/about/drive.png" alt=""></div>
 | 
			
		||||
				</section>
 | 
			
		||||
			</section>
 | 
			
		||||
			<p v-html="'%i18n:common.intro.outro%'"></p>
 | 
			
		||||
		</article>
 | 
			
		||||
	</modal>
 | 
			
		||||
 | 
			
		||||
	<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>
 | 
			
		||||
@@ -47,52 +145,62 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import { host, copyright } from '../../../config';
 | 
			
		||||
import { concat } from '../../../../../prelude/array';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			meta: null,
 | 
			
		||||
			stats: null,
 | 
			
		||||
			copyright,
 | 
			
		||||
			host,
 | 
			
		||||
			name: 'Misskey',
 | 
			
		||||
			description: '',
 | 
			
		||||
			pointerInterval: null,
 | 
			
		||||
			tags: []
 | 
			
		||||
			announcements: [],
 | 
			
		||||
			photos: []
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	created() {
 | 
			
		||||
		(this as any).os.getMeta().then(meta => {
 | 
			
		||||
			this.meta = meta;
 | 
			
		||||
			this.name = meta.name;
 | 
			
		||||
			this.description = meta.description;
 | 
			
		||||
			this.announcements = 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);
 | 
			
		||||
		const image = [
 | 
			
		||||
			'image/jpeg',
 | 
			
		||||
			'image/png',
 | 
			
		||||
			'image/gif'
 | 
			
		||||
		];
 | 
			
		||||
 | 
			
		||||
		(this as any).api('notes/local-timeline', {
 | 
			
		||||
			fileType: image,
 | 
			
		||||
			limit: 6
 | 
			
		||||
		}).then((notes: any[]) => {
 | 
			
		||||
			const files = concat(notes.map((n: any): any[] => n.files));
 | 
			
		||||
			this.photos = files.filter(f => image.includes(f.type)).slice(0, 6);
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	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';
 | 
			
		||||
		about() {
 | 
			
		||||
			this.$modal.show('about');
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		signup() {
 | 
			
		||||
			this.$modal.show('signup');
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		signin() {
 | 
			
		||||
			this.$modal.show('signin');
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		dark() {
 | 
			
		||||
			this.$store.commit('device/set', {
 | 
			
		||||
				key: 'darkmode',
 | 
			
		||||
@@ -103,11 +211,88 @@ 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
 | 
			
		||||
 | 
			
		||||
.v--modal-overlay.about
 | 
			
		||||
	.v--modal-box.v--modal
 | 
			
		||||
		margin 32px 0
 | 
			
		||||
 | 
			
		||||
.fpdezooorhntlzyeszemrsqdlgbysvxq
 | 
			
		||||
	padding 64px
 | 
			
		||||
 | 
			
		||||
	> p:last-child
 | 
			
		||||
		margin-bottom 0
 | 
			
		||||
 | 
			
		||||
	> h1
 | 
			
		||||
		margin-top 0
 | 
			
		||||
 | 
			
		||||
	> section
 | 
			
		||||
		> h2
 | 
			
		||||
			border-bottom 1px solid isDark ? rgba(#000, 0.2) : rgba(#000, 0.05)
 | 
			
		||||
 | 
			
		||||
		> section
 | 
			
		||||
			display grid
 | 
			
		||||
			grid-template-rows 1fr
 | 
			
		||||
			grid-template-columns 180px 1fr
 | 
			
		||||
			gap 32px
 | 
			
		||||
			margin-bottom 32px
 | 
			
		||||
			padding-bottom 32px
 | 
			
		||||
			border-bottom 1px solid isDark ? rgba(#000, 0.2) : rgba(#000, 0.05)
 | 
			
		||||
 | 
			
		||||
			&:nth-child(odd)
 | 
			
		||||
				grid-template-columns 1fr 180px
 | 
			
		||||
 | 
			
		||||
				> .body
 | 
			
		||||
					grid-column 1
 | 
			
		||||
 | 
			
		||||
				> .image
 | 
			
		||||
					grid-column 2
 | 
			
		||||
 | 
			
		||||
			> .body
 | 
			
		||||
				grid-row 1
 | 
			
		||||
				grid-column 2
 | 
			
		||||
 | 
			
		||||
			> .image
 | 
			
		||||
				grid-row 1
 | 
			
		||||
				grid-column 1
 | 
			
		||||
 | 
			
		||||
				> img
 | 
			
		||||
					display block
 | 
			
		||||
					width 100%
 | 
			
		||||
					height 100%
 | 
			
		||||
					object-fit cover
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
@@ -116,145 +301,191 @@ 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
 | 
			
		||||
		color isDark ? #fff : #444
 | 
			
		||||
 | 
			
		||||
		display none // TODO
 | 
			
		||||
	> main
 | 
			
		||||
		margin 0 auto
 | 
			
		||||
		padding 64px
 | 
			
		||||
		width 100%
 | 
			
		||||
		max-width 1200px
 | 
			
		||||
 | 
			
		||||
	> .body
 | 
			
		||||
		flex 1
 | 
			
		||||
		padding 64px 0 0 0
 | 
			
		||||
		text-align center
 | 
			
		||||
		background #578394
 | 
			
		||||
		background-position center
 | 
			
		||||
		background-size cover
 | 
			
		||||
		.block
 | 
			
		||||
			color isDark ? #fff : #444
 | 
			
		||||
			background isDark ? #282C37 : #fff
 | 
			
		||||
			box-shadow 0 3px 8px rgba(0, 0, 0, 0.2)
 | 
			
		||||
			//border-radius 8px
 | 
			
		||||
			overflow auto
 | 
			
		||||
 | 
			
		||||
		&:before
 | 
			
		||||
			content ''
 | 
			
		||||
			display block
 | 
			
		||||
			position absolute
 | 
			
		||||
			top 0
 | 
			
		||||
			left 0
 | 
			
		||||
			right 0
 | 
			
		||||
			bottom 0
 | 
			
		||||
			background rgba(#000, 0.5)
 | 
			
		||||
			> header
 | 
			
		||||
				z-index 1
 | 
			
		||||
				padding 0 16px
 | 
			
		||||
				line-height 48px
 | 
			
		||||
				background isDark ? #313543 : #fff
 | 
			
		||||
 | 
			
		||||
		> .forkit
 | 
			
		||||
			position absolute
 | 
			
		||||
			top 0
 | 
			
		||||
			right 0
 | 
			
		||||
				if !isDark
 | 
			
		||||
					box-shadow 0 1px 0px rgba(0, 0, 0, 0.1)
 | 
			
		||||
 | 
			
		||||
		> img
 | 
			
		||||
			position absolute
 | 
			
		||||
			bottom 16px
 | 
			
		||||
			right 16px
 | 
			
		||||
			width 150px
 | 
			
		||||
				& + div
 | 
			
		||||
					max-height calc(100% - 48px)
 | 
			
		||||
 | 
			
		||||
		> .container
 | 
			
		||||
			$aboutWidth = 380px
 | 
			
		||||
			$loginWidth = 340px
 | 
			
		||||
			$width = $aboutWidth + $loginWidth
 | 
			
		||||
			> div
 | 
			
		||||
				overflow auto
 | 
			
		||||
 | 
			
		||||
			> .info
 | 
			
		||||
				margin 0 auto 16px auto
 | 
			
		||||
				width $width
 | 
			
		||||
				font-size 14px
 | 
			
		||||
				color #fff
 | 
			
		||||
		> .body
 | 
			
		||||
			display grid
 | 
			
		||||
			grid-template-rows 1fr 1fr 256px 64px
 | 
			
		||||
			grid-template-columns 1fr 1fr 350px
 | 
			
		||||
			gap 16px
 | 
			
		||||
			height 1200px
 | 
			
		||||
 | 
			
		||||
				> .stats
 | 
			
		||||
					margin-left 16px
 | 
			
		||||
					padding-left 16px
 | 
			
		||||
					border-left solid 1px #fff
 | 
			
		||||
			> .main
 | 
			
		||||
				grid-row 1
 | 
			
		||||
				grid-column 1 / 3
 | 
			
		||||
				border-top solid 5px $theme-color
 | 
			
		||||
 | 
			
		||||
					> *
 | 
			
		||||
						margin-right 16px
 | 
			
		||||
 | 
			
		||||
			> main
 | 
			
		||||
				display flex
 | 
			
		||||
				margin auto
 | 
			
		||||
				width $width
 | 
			
		||||
				border-radius 8px
 | 
			
		||||
				overflow hidden
 | 
			
		||||
				box-shadow 0 2px 8px rgba(#000, 0.3)
 | 
			
		||||
 | 
			
		||||
				> .about
 | 
			
		||||
					width $aboutWidth
 | 
			
		||||
					color #444
 | 
			
		||||
					background #fff
 | 
			
		||||
				> div
 | 
			
		||||
					padding 32px
 | 
			
		||||
					min-height 100%
 | 
			
		||||
 | 
			
		||||
					> h1
 | 
			
		||||
						margin 0 0 16px 0
 | 
			
		||||
						padding 32px 32px 0 32px
 | 
			
		||||
						color #444
 | 
			
		||||
						margin 0
 | 
			
		||||
 | 
			
		||||
						> img
 | 
			
		||||
							width 170px
 | 
			
		||||
							vertical-align bottom
 | 
			
		||||
							margin -8px 0 0 -16px
 | 
			
		||||
							max-width 280px
 | 
			
		||||
 | 
			
		||||
					> .powerd-by
 | 
			
		||||
						margin 16px
 | 
			
		||||
						opacity 0.7
 | 
			
		||||
					> .info
 | 
			
		||||
						margin 0 auto 16px auto
 | 
			
		||||
						width $width
 | 
			
		||||
						font-size 14px
 | 
			
		||||
 | 
			
		||||
					> .desc
 | 
			
		||||
						margin 0
 | 
			
		||||
						padding 0 32px 16px 32px
 | 
			
		||||
						> .stats
 | 
			
		||||
							margin-left 16px
 | 
			
		||||
							padding-left 16px
 | 
			
		||||
							border-left solid 1px isDark ? #fff : #444
 | 
			
		||||
 | 
			
		||||
					> a
 | 
			
		||||
						display inline-block
 | 
			
		||||
						margin 0 0 32px 0
 | 
			
		||||
						font-weight bold
 | 
			
		||||
							> *
 | 
			
		||||
								margin-right 16px
 | 
			
		||||
 | 
			
		||||
				> .login
 | 
			
		||||
					width $loginWidth
 | 
			
		||||
					padding 16px 32px 32px 32px
 | 
			
		||||
					background isDark ? #2e3440 : #f5f5f5
 | 
			
		||||
					> .sign
 | 
			
		||||
						font-size 120%
 | 
			
		||||
 | 
			
		||||
			> .hashtags
 | 
			
		||||
				margin 16px auto
 | 
			
		||||
				width $width
 | 
			
		||||
				font-size 14px
 | 
			
		||||
				color #fff
 | 
			
		||||
				background rgba(#000, 0.3)
 | 
			
		||||
				border-radius 8px
 | 
			
		||||
						> .divider
 | 
			
		||||
							margin 0 16px
 | 
			
		||||
 | 
			
		||||
				> *
 | 
			
		||||
					display inline-block
 | 
			
		||||
					margin 14px
 | 
			
		||||
						> .signin
 | 
			
		||||
						> .signup
 | 
			
		||||
							cursor pointer
 | 
			
		||||
 | 
			
		||||
							&:hover
 | 
			
		||||
								color $theme-color
 | 
			
		||||
 | 
			
		||||
					> .char
 | 
			
		||||
						display block
 | 
			
		||||
						position absolute
 | 
			
		||||
						right 16px
 | 
			
		||||
						bottom 16px
 | 
			
		||||
						width 180px
 | 
			
		||||
						opacity 0.3
 | 
			
		||||
 | 
			
		||||
					> *:not(.char)
 | 
			
		||||
						z-index 1
 | 
			
		||||
 | 
			
		||||
			> .announcements
 | 
			
		||||
				grid-row 2
 | 
			
		||||
				grid-column 1
 | 
			
		||||
 | 
			
		||||
				> div
 | 
			
		||||
					padding 32px
 | 
			
		||||
 | 
			
		||||
					> div
 | 
			
		||||
						padding 0 0 16px 0
 | 
			
		||||
						margin 0 0 16px 0
 | 
			
		||||
						border-bottom 1px solid isDark ? rgba(#000, 0.2) : rgba(#000, 0.05)
 | 
			
		||||
 | 
			
		||||
						> h1
 | 
			
		||||
							margin 0
 | 
			
		||||
							font-size 1.25em
 | 
			
		||||
 | 
			
		||||
			> .photos
 | 
			
		||||
				grid-row 2
 | 
			
		||||
				grid-column 2
 | 
			
		||||
 | 
			
		||||
				> div
 | 
			
		||||
					display grid
 | 
			
		||||
					grid-template-rows 1fr 1fr 1fr
 | 
			
		||||
					grid-template-columns 1fr 1fr
 | 
			
		||||
					gap 8px
 | 
			
		||||
					height 100%
 | 
			
		||||
					padding 16px
 | 
			
		||||
 | 
			
		||||
					> div
 | 
			
		||||
						//border-radius 4px
 | 
			
		||||
						background-position center center
 | 
			
		||||
						background-size cover
 | 
			
		||||
 | 
			
		||||
			> .tag-cloud
 | 
			
		||||
				grid-row 3
 | 
			
		||||
				grid-column 1 / 3
 | 
			
		||||
 | 
			
		||||
				> div
 | 
			
		||||
					height 256px
 | 
			
		||||
					padding 32px
 | 
			
		||||
 | 
			
		||||
			> .nav
 | 
			
		||||
				display block
 | 
			
		||||
				margin 16px 0
 | 
			
		||||
				display flex
 | 
			
		||||
				justify-content center
 | 
			
		||||
				align-items center
 | 
			
		||||
				grid-row 4
 | 
			
		||||
				grid-column 1 / 3
 | 
			
		||||
				font-size 14px
 | 
			
		||||
				color #fff
 | 
			
		||||
 | 
			
		||||
	> .tl
 | 
			
		||||
		margin 0
 | 
			
		||||
		width 410px
 | 
			
		||||
		height 100vh
 | 
			
		||||
		text-align left
 | 
			
		||||
		background isDark ? #313543 : #fff
 | 
			
		||||
			> .side
 | 
			
		||||
				display grid
 | 
			
		||||
				grid-row 1 / 5
 | 
			
		||||
				grid-column 3
 | 
			
		||||
				grid-template-rows 1fr 350px
 | 
			
		||||
				grid-template-columns 1fr
 | 
			
		||||
				gap 16px
 | 
			
		||||
 | 
			
		||||
		> *
 | 
			
		||||
			max-height 100%
 | 
			
		||||
			overflow auto
 | 
			
		||||
				> .tl
 | 
			
		||||
					grid-row 1
 | 
			
		||||
					grid-column 1
 | 
			
		||||
					overflow auto
 | 
			
		||||
 | 
			
		||||
				> .trends
 | 
			
		||||
					grid-row 2
 | 
			
		||||
					grid-column 1
 | 
			
		||||
					padding 8px
 | 
			
		||||
 | 
			
		||||
				> .info
 | 
			
		||||
					grid-row 3
 | 
			
		||||
					grid-column 1
 | 
			
		||||
 | 
			
		||||
					> div
 | 
			
		||||
						padding 16px
 | 
			
		||||
 | 
			
		||||
						> .body
 | 
			
		||||
							> p
 | 
			
		||||
								display block
 | 
			
		||||
								margin 0
 | 
			
		||||
 | 
			
		||||
.mk-welcome[data-darkmode]
 | 
			
		||||
	root(true)
 | 
			
		||||
@@ -263,29 +494,3 @@ root(isDark)
 | 
			
		||||
	root(false)
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" module>
 | 
			
		||||
.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>
 | 
			
		||||
 
 | 
			
		||||
@@ -49,7 +49,7 @@ export default define({
 | 
			
		||||
				offset: this.offset,
 | 
			
		||||
				renote: false,
 | 
			
		||||
				reply: false,
 | 
			
		||||
				media: false,
 | 
			
		||||
				file: false,
 | 
			
		||||
				poll: false
 | 
			
		||||
			}).then(notes => {
 | 
			
		||||
				const note = notes ? notes[0] : null;
 | 
			
		||||
 
 | 
			
		||||
@@ -5,14 +5,12 @@
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import Vuex from 'vuex';
 | 
			
		||||
import VueRouter from 'vue-router';
 | 
			
		||||
import VModal from 'vue-js-modal';
 | 
			
		||||
import * as TreeView from 'vue-json-tree-view';
 | 
			
		||||
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';
 | 
			
		||||
@@ -28,13 +26,10 @@ switch (lang) {
 | 
			
		||||
 | 
			
		||||
Vue.use(Vuex);
 | 
			
		||||
Vue.use(VueRouter);
 | 
			
		||||
Vue.use(VModal);
 | 
			
		||||
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');
 | 
			
		||||
 
 | 
			
		||||
@@ -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';
 | 
			
		||||
@@ -17,6 +17,7 @@ import Err from './common/views/components/connect-failed.vue';
 | 
			
		||||
import { LocalTimelineStreamManager } from './common/scripts/streaming/local-timeline';
 | 
			
		||||
import { HybridTimelineStreamManager } from './common/scripts/streaming/hybrid-timeline';
 | 
			
		||||
import { GlobalTimelineStreamManager } from './common/scripts/streaming/global-timeline';
 | 
			
		||||
import { erase } from '../../prelude/array';
 | 
			
		||||
 | 
			
		||||
//#region api requests
 | 
			
		||||
let spinner = null;
 | 
			
		||||
@@ -230,13 +231,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 +362,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
 | 
			
		||||
@@ -537,7 +538,7 @@ export default class MiOS extends EventEmitter {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public unregisterStreamConnection(connection: Connection) {
 | 
			
		||||
		this.connections = this.connections.filter(c => c != connection);
 | 
			
		||||
		this.connections = erase(connection, this.connections);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										23
									
								
								src/client/app/mobile/api/post.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/client/app/mobile/api/post.ts
									
									
									
									
									
										Normal 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();
 | 
			
		||||
};
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -17,13 +17,3 @@ body
 | 
			
		||||
	display flex
 | 
			
		||||
	flex-direction column
 | 
			
		||||
	min-height 100%
 | 
			
		||||
 | 
			
		||||
.modal-backdrop
 | 
			
		||||
	z-index 10000 !important
 | 
			
		||||
 | 
			
		||||
.modal-content-wrapper
 | 
			
		||||
	z-index 10001 !important
 | 
			
		||||
 | 
			
		||||
.modal-content
 | 
			
		||||
	padding 0 !important
 | 
			
		||||
	background-color transparent !important
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user