Compare commits
	
		
			306 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					ea60565b0d | ||
| 
						 | 
					a26585dcc7 | ||
| 
						 | 
					008e5bd24c | ||
| 
						 | 
					ebc6564fbb | ||
| 
						 | 
					06b5078245 | ||
| 
						 | 
					68337f95ff | ||
| 
						 | 
					72e148002a | ||
| 
						 | 
					f0a03f71eb | ||
| 
						 | 
					6049473e46 | ||
| 
						 | 
					f9f2787dfc | ||
| 
						 | 
					b0a068e269 | ||
| 
						 | 
					dd5546690a | ||
| 
						 | 
					d87b6d38ab | ||
| 
						 | 
					4069bb170a | ||
| 
						 | 
					600c009549 | ||
| 
						 | 
					c953a28201 | ||
| 
						 | 
					f6541df42a | ||
| 
						 | 
					a57e9460c8 | ||
| 
						 | 
					c7bcf31105 | ||
| 
						 | 
					a397c040fe | ||
| 
						 | 
					e311d73ffc | ||
| 
						 | 
					2a3599a14d | ||
| 
						 | 
					b85dc8a658 | ||
| 
						 | 
					7513123052 | ||
| 
						 | 
					2526b86ec5 | ||
| 
						 | 
					e45aa0532c | ||
| 
						 | 
					71fc84e224 | ||
| 
						 | 
					6b726eea39 | ||
| 
						 | 
					acd4b101e1 | ||
| 
						 | 
					98b8a94f2b | ||
| 
						 | 
					7d31bd97ff | ||
| 
						 | 
					828a2a73c9 | ||
| 
						 | 
					bdc7167cf4 | ||
| 
						 | 
					45b94086ed | ||
| 
						 | 
					e62bb7cdaf | ||
| 
						 | 
					c5f65d9eeb | ||
| 
						 | 
					4557856104 | ||
| 
						 | 
					4a23c36740 | ||
| 
						 | 
					2553b20130 | ||
| 
						 | 
					6982faf668 | ||
| 
						 | 
					4db972318f | ||
| 
						 | 
					81006566a5 | ||
| 
						 | 
					6abc053a48 | ||
| 
						 | 
					155da0c6a3 | ||
| 
						 | 
					03a3c56a54 | ||
| 
						 | 
					83b7010d6a | ||
| 
						 | 
					71654cbe47 | ||
| 
						 | 
					e8f96e848a | ||
| 
						 | 
					251abf21d4 | ||
| 
						 | 
					d103427932 | ||
| 
						 | 
					592cdfa910 | ||
| 
						 | 
					f2ad1a0406 | ||
| 
						 | 
					82af9320c0 | ||
| 
						 | 
					fceebf7388 | ||
| 
						 | 
					13caf37991 | ||
| 
						 | 
					b71a602107 | ||
| 
						 | 
					e6ce0dd43a | ||
| 
						 | 
					094a5214f1 | ||
| 
						 | 
					0932fcd114 | ||
| 
						 | 
					f26643cea3 | ||
| 
						 | 
					63b1689155 | ||
| 
						 | 
					59dc929431 | ||
| 
						 | 
					deaadc33db | ||
| 
						 | 
					0ba92a4f29 | ||
| 
						 | 
					7dc5009ec7 | ||
| 
						 | 
					0ee827afd3 | ||
| 
						 | 
					551d1b7f86 | ||
| 
						 | 
					7ed1b695f5 | ||
| 
						 | 
					7ad31b9b33 | ||
| 
						 | 
					edd8992f7f | ||
| 
						 | 
					96fe42cfcb | ||
| 
						 | 
					c3872b4a38 | ||
| 
						 | 
					762945113d | ||
| 
						 | 
					037e9230fc | ||
| 
						 | 
					3f59ebf986 | ||
| 
						 | 
					e51e1d2b09 | ||
| 
						 | 
					26cc49eb69 | ||
| 
						 | 
					7987bb491c | ||
| 
						 | 
					16b7ac5a87 | ||
| 
						 | 
					5932cb8609 | ||
| 
						 | 
					dfe694d39f | ||
| 
						 | 
					278624f2c8 | ||
| 
						 | 
					899f42c070 | ||
| 
						 | 
					8ce1d4d6a3 | ||
| 
						 | 
					52225d703b | ||
| 
						 | 
					81739af7cb | ||
| 
						 | 
					25473222cc | ||
| 
						 | 
					0b7be70935 | ||
| 
						 | 
					818b71abd6 | ||
| 
						 | 
					25575e8510 | ||
| 
						 | 
					6c85adcf23 | ||
| 
						 | 
					5dc92d7a40 | ||
| 
						 | 
					4e2b966b80 | ||
| 
						 | 
					d34f8c3cb9 | ||
| 
						 | 
					9049ecb1cf | ||
| 
						 | 
					7bebea087c | ||
| 
						 | 
					1c79e30436 | ||
| 
						 | 
					1d7933349b | ||
| 
						 | 
					d002f67140 | ||
| 
						 | 
					da3447765b | ||
| 
						 | 
					cbf5663179 | ||
| 
						 | 
					b217fba235 | ||
| 
						 | 
					7f7e6d5aba | ||
| 
						 | 
					87c5a9d9a6 | ||
| 
						 | 
					8ca1fe3f0a | ||
| 
						 | 
					763ae8f1a6 | ||
| 
						 | 
					c65256d02b | ||
| 
						 | 
					bd2ac515d1 | ||
| 
						 | 
					681f372889 | ||
| 
						 | 
					c2eec272e6 | ||
| 
						 | 
					bd720491a9 | ||
| 
						 | 
					a408226509 | ||
| 
						 | 
					c015e99e6e | ||
| 
						 | 
					de47a17be7 | ||
| 
						 | 
					d38fc490ad | ||
| 
						 | 
					662167e792 | ||
| 
						 | 
					36c91f03d9 | ||
| 
						 | 
					33ccee26b5 | ||
| 
						 | 
					ed5cb991e3 | ||
| 
						 | 
					bea84ec2bf | ||
| 
						 | 
					08c176e549 | ||
| 
						 | 
					810ed50976 | ||
| 
						 | 
					2684541693 | ||
| 
						 | 
					a5b12bac54 | ||
| 
						 | 
					fea1b06e43 | ||
| 
						 | 
					182ca5d434 | ||
| 
						 | 
					facde9a75d | ||
| 
						 | 
					41385640b9 | ||
| 
						 | 
					7bad9db32e | ||
| 
						 | 
					af66f0a497 | ||
| 
						 | 
					95e1b80f41 | ||
| 
						 | 
					556e2eba95 | ||
| 
						 | 
					efe530cb17 | ||
| 
						 | 
					34e7c99283 | ||
| 
						 | 
					4157ea8bc3 | ||
| 
						 | 
					550517bbf3 | ||
| 
						 | 
					eb910cd8a1 | ||
| 
						 | 
					75131c4e8a | ||
| 
						 | 
					ee29ab95be | ||
| 
						 | 
					e97951fc51 | ||
| 
						 | 
					dfabdef60f | ||
| 
						 | 
					5a87763193 | ||
| 
						 | 
					6bb90f56fa | ||
| 
						 | 
					c883ae1350 | ||
| 
						 | 
					09e25e6a02 | ||
| 
						 | 
					bf5d43054b | ||
| 
						 | 
					63b3c65691 | ||
| 
						 | 
					f193da7f67 | ||
| 
						 | 
					40f38c2c0a | ||
| 
						 | 
					db439ef804 | ||
| 
						 | 
					56eb896a03 | ||
| 
						 | 
					68d43e43b6 | ||
| 
						 | 
					c60517e49a | ||
| 
						 | 
					3f59d261f2 | ||
| 
						 | 
					4068d220e5 | ||
| 
						 | 
					18968e7208 | ||
| 
						 | 
					38656103c0 | ||
| 
						 | 
					0f65b1bcc5 | ||
| 
						 | 
					a628821834 | ||
| 
						 | 
					6ceff60c1e | ||
| 
						 | 
					d762a6ce58 | ||
| 
						 | 
					75a8037a46 | ||
| 
						 | 
					1179920790 | ||
| 
						 | 
					b323a160e3 | ||
| 
						 | 
					b157e9535e | ||
| 
						 | 
					7668475bd6 | ||
| 
						 | 
					8bda2a1fb7 | ||
| 
						 | 
					b092086b5b | ||
| 
						 | 
					69a0d9034f | ||
| 
						 | 
					f5be8fd313 | ||
| 
						 | 
					7f835d7f76 | ||
| 
						 | 
					ddbb7c5993 | ||
| 
						 | 
					00a3fe39e8 | ||
| 
						 | 
					7537fb88d4 | ||
| 
						 | 
					a81bc71a1e | ||
| 
						 | 
					0a0aa0e2db | ||
| 
						 | 
					c56b94ae96 | ||
| 
						 | 
					e90712706d | ||
| 
						 | 
					eb0623331f | ||
| 
						 | 
					d15bd59109 | ||
| 
						 | 
					60e0b19372 | ||
| 
						 | 
					922eb937ff | ||
| 
						 | 
					87573284f1 | ||
| 
						 | 
					a91c585f55 | ||
| 
						 | 
					953ea21d5e | ||
| 
						 | 
					ecb00968bc | ||
| 
						 | 
					50ad8adb2d | ||
| 
						 | 
					16878caf09 | ||
| 
						 | 
					5bc30c5493 | ||
| 
						 | 
					85d89cf4c4 | ||
| 
						 | 
					db693f598b | ||
| 
						 | 
					0494c770a1 | ||
| 
						 | 
					c473b62aed | ||
| 
						 | 
					f19ac5320e | ||
| 
						 | 
					612e3aafbc | ||
| 
						 | 
					0e97fec451 | ||
| 
						 | 
					e8c8626ee4 | ||
| 
						 | 
					d89e0f07f8 | ||
| 
						 | 
					e7f81a42ce | ||
| 
						 | 
					ac614148b8 | ||
| 
						 | 
					5eb02b4901 | ||
| 
						 | 
					65631525f6 | ||
| 
						 | 
					969435cfe9 | ||
| 
						 | 
					c932f7a25b | ||
| 
						 | 
					42d164dc57 | ||
| 
						 | 
					a7e60f80bd | ||
| 
						 | 
					3dd5f313b7 | ||
| 
						 | 
					883962c393 | ||
| 
						 | 
					8a30ff1c76 | ||
| 
						 | 
					e47c354916 | ||
| 
						 | 
					496f42805d | ||
| 
						 | 
					c3d34bda37 | ||
| 
						 | 
					bb6ede2b8f | ||
| 
						 | 
					822400a1ba | ||
| 
						 | 
					e3e08843f1 | ||
| 
						 | 
					ce0d4f77fa | ||
| 
						 | 
					94fdb4e974 | ||
| 
						 | 
					4d425fc8a4 | ||
| 
						 | 
					c6cdfa2f5a | ||
| 
						 | 
					0fff2e4f16 | ||
| 
						 | 
					80a2172715 | ||
| 
						 | 
					5a0a297634 | ||
| 
						 | 
					948a133b7b | ||
| 
						 | 
					2ee826c958 | ||
| 
						 | 
					539409faf8 | ||
| 
						 | 
					606e46e4d7 | ||
| 
						 | 
					a179cfd69a | ||
| 
						 | 
					d8379253d4 | ||
| 
						 | 
					c3344fbd68 | ||
| 
						 | 
					4cebd6e84a | ||
| 
						 | 
					90fbf9dbb0 | ||
| 
						 | 
					d365b9f634 | ||
| 
						 | 
					a2f06acaa4 | ||
| 
						 | 
					8c90cbcbfb | ||
| 
						 | 
					a4a47772dc | ||
| 
						 | 
					5dde1f4602 | ||
| 
						 | 
					9dc0909eeb | ||
| 
						 | 
					0ed2592e41 | ||
| 
						 | 
					76cff98220 | ||
| 
						 | 
					60604b6f51 | ||
| 
						 | 
					f410b7aecb | ||
| 
						 | 
					1a61f2cee9 | ||
| 
						 | 
					78a8293520 | ||
| 
						 | 
					03cfb4fc8d | ||
| 
						 | 
					144345a359 | ||
| 
						 | 
					fd2c01515e | ||
| 
						 | 
					219570e08b | ||
| 
						 | 
					69df556ff5 | ||
| 
						 | 
					5f4a52574f | ||
| 
						 | 
					5a1f6c5839 | ||
| 
						 | 
					91d0342fe8 | ||
| 
						 | 
					8cc236daf8 | ||
| 
						 | 
					d283ec69f7 | ||
| 
						 | 
					d1aea7596c | ||
| 
						 | 
					c934987b14 | ||
| 
						 | 
					00c9f4a2e5 | ||
| 
						 | 
					6605c1d07f | ||
| 
						 | 
					7325d66c52 | ||
| 
						 | 
					a485061e22 | ||
| 
						 | 
					1f63f50343 | ||
| 
						 | 
					cd3170dabd | ||
| 
						 | 
					841cedc5f8 | ||
| 
						 | 
					7f4882734d | ||
| 
						 | 
					e7d647d412 | ||
| 
						 | 
					913d14a58a | ||
| 
						 | 
					909272ec3d | ||
| 
						 | 
					7af40ffbbe | ||
| 
						 | 
					9df79a3ec9 | ||
| 
						 | 
					4f2eee06aa | ||
| 
						 | 
					1b9cf76008 | ||
| 
						 | 
					d035a43ed6 | ||
| 
						 | 
					95ee9a6e09 | ||
| 
						 | 
					02a63cdcb3 | ||
| 
						 | 
					f02125dd47 | ||
| 
						 | 
					c11e813146 | ||
| 
						 | 
					a365849048 | ||
| 
						 | 
					a493c9f769 | ||
| 
						 | 
					a13f522b2a | ||
| 
						 | 
					1ed70b2e2c | ||
| 
						 | 
					86d5a599b7 | ||
| 
						 | 
					c226fc8d63 | ||
| 
						 | 
					bbf4e1c413 | ||
| 
						 | 
					a24a20a83d | ||
| 
						 | 
					725600da8f | ||
| 
						 | 
					f74a32ed9b | ||
| 
						 | 
					e08e72dd10 | ||
| 
						 | 
					ce02e1e528 | ||
| 
						 | 
					0b27d8a717 | ||
| 
						 | 
					2782e7d26f | ||
| 
						 | 
					2c83a05e80 | ||
| 
						 | 
					467f68502a | ||
| 
						 | 
					d95b0dee6b | ||
| 
						 | 
					a1f3323fa5 | ||
| 
						 | 
					494796a7f0 | ||
| 
						 | 
					94f2c20d35 | ||
| 
						 | 
					c1deb9438d | ||
| 
						 | 
					ea86527c66 | ||
| 
						 | 
					d1a18fe266 | ||
| 
						 | 
					737064da82 | ||
| 
						 | 
					606cc85ff5 | ||
| 
						 | 
					dcfc8f1b30 | ||
| 
						 | 
					ebe4b84f14 | ||
| 
						 | 
					699d4897db | ||
| 
						 | 
					fcdfd8d323 | ||
| 
						 | 
					db8625c31a | ||
| 
						 | 
					b65f265c55 | 
@@ -53,40 +53,54 @@ mongodb:
 | 
			
		||||
drive:
 | 
			
		||||
  storage: 'db'
 | 
			
		||||
 | 
			
		||||
  # OR
 | 
			
		||||
# OR
 | 
			
		||||
 | 
			
		||||
  # storage: 'minio'
 | 
			
		||||
  # bucket:
 | 
			
		||||
  # prefix:
 | 
			
		||||
  # config:
 | 
			
		||||
  #   endPoint:
 | 
			
		||||
  #   port:
 | 
			
		||||
  #   useSSL:
 | 
			
		||||
  #   accessKey:
 | 
			
		||||
  #   secretKey:
 | 
			
		||||
#drive:
 | 
			
		||||
#  storage: 'minio'
 | 
			
		||||
#  bucket:
 | 
			
		||||
#  prefix:
 | 
			
		||||
#  config:
 | 
			
		||||
#    endPoint:
 | 
			
		||||
#    port:
 | 
			
		||||
#    useSSL:
 | 
			
		||||
#    accessKey:
 | 
			
		||||
#    secretKey:
 | 
			
		||||
 | 
			
		||||
  # S3 example
 | 
			
		||||
  # storage: 'minio'
 | 
			
		||||
  # bucket: bucket-name
 | 
			
		||||
  # prefix: files
 | 
			
		||||
  # config:
 | 
			
		||||
  #   endPoint: s3-us-west-2.amazonaws.com
 | 
			
		||||
  #   region: us-west-2
 | 
			
		||||
  #   useSSL: true
 | 
			
		||||
  #   accessKey: XXX
 | 
			
		||||
  #   secretKey: YYY
 | 
			
		||||
# S3/GCS example
 | 
			
		||||
#
 | 
			
		||||
# * Replace <endpoint> to
 | 
			
		||||
#     S3: see https://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region
 | 
			
		||||
#     GCS: use 'storage.googleapis.com'
 | 
			
		||||
#
 | 
			
		||||
# * Replace <region> to
 | 
			
		||||
#     S3: see https://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region
 | 
			
		||||
#     GCS: not needed (just delete the region line)
 | 
			
		||||
#
 | 
			
		||||
#drive:
 | 
			
		||||
#  storage: 'minio'
 | 
			
		||||
#  bucket: bucket-name
 | 
			
		||||
#  prefix: files
 | 
			
		||||
#  baseUrl: https://bucket-name.<endpoint>
 | 
			
		||||
#  config:
 | 
			
		||||
#    endPoint: <endpoint>
 | 
			
		||||
#    region: <region>
 | 
			
		||||
#    useSSL: true
 | 
			
		||||
#    accessKey: XXX
 | 
			
		||||
#    secretKey: YYY
 | 
			
		||||
 | 
			
		||||
  # S3 example (with CDN, custom domain)
 | 
			
		||||
  # storage: 'minio'
 | 
			
		||||
  # bucket: drive.example.com
 | 
			
		||||
  # prefix: files
 | 
			
		||||
  # baseUrl: https://drive.example.com
 | 
			
		||||
  # config:
 | 
			
		||||
  #   endPoint: s3-us-west-2.amazonaws.com
 | 
			
		||||
  #   region: us-west-2
 | 
			
		||||
  #   useSSL: true
 | 
			
		||||
  #   accessKey: XXX
 | 
			
		||||
  #   secretKey: YYY
 | 
			
		||||
# S3/GCS example (with CDN, custom domain)
 | 
			
		||||
#
 | 
			
		||||
#drive:
 | 
			
		||||
#  storage: 'minio'
 | 
			
		||||
#  bucket: drive.example.com
 | 
			
		||||
#  prefix: files
 | 
			
		||||
#  baseUrl: https://drive.example.com
 | 
			
		||||
#  config:
 | 
			
		||||
#    endPoint: <endpoint>
 | 
			
		||||
#    region: <region>
 | 
			
		||||
#    useSSL: true
 | 
			
		||||
#    accessKey: XXX
 | 
			
		||||
#    secretKey: YYY
 | 
			
		||||
 | 
			
		||||
# If enabled:
 | 
			
		||||
#  The first account created is automatically marked as Admin.
 | 
			
		||||
@@ -113,3 +127,6 @@ autoAdmin: true
 | 
			
		||||
 | 
			
		||||
# Clustering
 | 
			
		||||
#clusterLimit: 1
 | 
			
		||||
 | 
			
		||||
# IP address family used for outgoing request (ipv4, ipv6 or dual)
 | 
			
		||||
#outgoingAddressFamily: ipv4
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								.github/CODEOWNERS
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/CODEOWNERS
									
									
									
									
										vendored
									
									
								
							@@ -1,7 +1,7 @@
 | 
			
		||||
# PATH                                          OWNERS
 | 
			
		||||
/.autogen/                                      @acid-chicken
 | 
			
		||||
/.circleci/                                     @syuilo @acid-chicken
 | 
			
		||||
/.config/                                       @syuilo @AyaMorisawa @mei23 @acid-chicken
 | 
			
		||||
/.config/                                       @syuilo @AyaMorisawa @mei23 @acid-chicken @rinsuki
 | 
			
		||||
# /.config/mongo_initdb_example.js              @khws4v1
 | 
			
		||||
/.github/                                       @syuilo @AyaMorisawa @acid-chicken
 | 
			
		||||
/.vscode/                                       @acid-chicken
 | 
			
		||||
@@ -12,7 +12,7 @@
 | 
			
		||||
# /docs/*.fr.md                                 @BoFFire
 | 
			
		||||
# /docs/docker.*.md                             @khws4v1
 | 
			
		||||
/locales/                                       @syuilo
 | 
			
		||||
/src/                                           @syuilo @AyaMorisawa @mei23 @acid-chicken
 | 
			
		||||
/src/                                           @syuilo @AyaMorisawa @mei23 @acid-chicken @rinsuki
 | 
			
		||||
# /src/crypto_key.cc                            @akihikodaki
 | 
			
		||||
# /src/crypto_key.d.ts                          @akihikodaki
 | 
			
		||||
/.dockerignore                                  @syuilo # @khws4v1
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								.github/ISSUE_TEMPLATE/01_bug-report.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								.github/ISSUE_TEMPLATE/01_bug-report.md
									
									
									
									
										vendored
									
									
								
							@@ -1,30 +1,30 @@
 | 
			
		||||
---
 | 
			
		||||
name: Bug Report
 | 
			
		||||
name: 🐛 Bug Report
 | 
			
		||||
about: Create a report to help us improve
 | 
			
		||||
title: ''
 | 
			
		||||
labels: bug
 | 
			
		||||
labels: ⚠️bug?
 | 
			
		||||
assignees: ''
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# Summary
 | 
			
		||||
## 💡 Summary
 | 
			
		||||
 | 
			
		||||
<!-- Tell us what the bug is -->
 | 
			
		||||
 | 
			
		||||
# Expected Behavior
 | 
			
		||||
## 🙂 Expected Behavior
 | 
			
		||||
 | 
			
		||||
<!--- Tell us what should happen -->
 | 
			
		||||
 | 
			
		||||
# Actual Behavior
 | 
			
		||||
## ☹️ Actual Behavior
 | 
			
		||||
 | 
			
		||||
<!--- Tell us what happens instead of the expected behavior -->
 | 
			
		||||
 | 
			
		||||
# Steps to Reproduce
 | 
			
		||||
## 📝 Steps to Reproduce
 | 
			
		||||
 | 
			
		||||
1.
 | 
			
		||||
2.
 | 
			
		||||
3.
 | 
			
		||||
 | 
			
		||||
# Environment
 | 
			
		||||
## 📌 Environment
 | 
			
		||||
 | 
			
		||||
<!-- Tell us where on the platform it happens -->
 | 
			
		||||
 
 | 
			
		||||
@@ -1,31 +0,0 @@
 | 
			
		||||
---
 | 
			
		||||
name: Client-side Bug Report
 | 
			
		||||
about: Create a report to help us improve
 | 
			
		||||
title: ''
 | 
			
		||||
labels: bug, client-side
 | 
			
		||||
assignees: ''
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# Summary
 | 
			
		||||
 | 
			
		||||
<!-- Tell us what the bug is -->
 | 
			
		||||
 | 
			
		||||
# Expected Behavior
 | 
			
		||||
 | 
			
		||||
<!--- Tell us what should happen -->
 | 
			
		||||
 | 
			
		||||
# Actual Behavior
 | 
			
		||||
 | 
			
		||||
<!--- Tell us what happens instead of the expected behavior -->
 | 
			
		||||
 | 
			
		||||
# Steps to Reproduce
 | 
			
		||||
 | 
			
		||||
1.
 | 
			
		||||
2.
 | 
			
		||||
3.
 | 
			
		||||
 | 
			
		||||
# Environment
 | 
			
		||||
 | 
			
		||||
<!-- Tell us where on the platform it happens -->
 | 
			
		||||
<!-- e.g. desktop or mobile version, your browser, your OS -->
 | 
			
		||||
@@ -1,12 +1,12 @@
 | 
			
		||||
---
 | 
			
		||||
name: Feature Request
 | 
			
		||||
name: ✨ Feature Request
 | 
			
		||||
about: Suggest an idea for this project
 | 
			
		||||
title: ''
 | 
			
		||||
labels: feature
 | 
			
		||||
labels: ✨Feature
 | 
			
		||||
assignees: ''
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# Summary
 | 
			
		||||
## Summary
 | 
			
		||||
 | 
			
		||||
<!-- Tell us what the suggestion is -->
 | 
			
		||||
@@ -1,31 +0,0 @@
 | 
			
		||||
---
 | 
			
		||||
name: Server-side Bug Report
 | 
			
		||||
about: Create a report to help us improve
 | 
			
		||||
title: ''
 | 
			
		||||
labels: bug, server-side
 | 
			
		||||
assignees: ''
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# Summary
 | 
			
		||||
 | 
			
		||||
<!-- Tell us what the bug is -->
 | 
			
		||||
 | 
			
		||||
# Expected Behavior
 | 
			
		||||
 | 
			
		||||
<!--- Tell us what should happen -->
 | 
			
		||||
 | 
			
		||||
# Actual Behavior
 | 
			
		||||
 | 
			
		||||
<!--- Tell us what happens instead of the expected behavior -->
 | 
			
		||||
 | 
			
		||||
# Steps to Reproduce
 | 
			
		||||
 | 
			
		||||
1.
 | 
			
		||||
2.
 | 
			
		||||
3.
 | 
			
		||||
 | 
			
		||||
# Environment
 | 
			
		||||
 | 
			
		||||
<!-- Tell us where on the platform it happens -->
 | 
			
		||||
<!-- e.g. your Node.js version, your OS -->
 | 
			
		||||
@@ -1,12 +0,0 @@
 | 
			
		||||
---
 | 
			
		||||
name: Client-side Feature Request
 | 
			
		||||
about: Suggest an idea for this project
 | 
			
		||||
title: ''
 | 
			
		||||
labels: client-side, feature
 | 
			
		||||
assignees: ''
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# Summary
 | 
			
		||||
 | 
			
		||||
<!-- Tell us what the suggestion is -->
 | 
			
		||||
@@ -1,12 +0,0 @@
 | 
			
		||||
---
 | 
			
		||||
name: Server-side Feature Request
 | 
			
		||||
about: Suggest an idea for this project
 | 
			
		||||
title: ''
 | 
			
		||||
labels: feature, server-side
 | 
			
		||||
assignees: ''
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# Summary
 | 
			
		||||
 | 
			
		||||
<!-- Tell us what the suggestion is -->
 | 
			
		||||
							
								
								
									
										2
									
								
								.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							@@ -1,4 +1,4 @@
 | 
			
		||||
# Summary
 | 
			
		||||
## Summary
 | 
			
		||||
 | 
			
		||||
<!--
 | 
			
		||||
  -
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -19,3 +19,4 @@ api-docs.json
 | 
			
		||||
*.code-workspace
 | 
			
		||||
yarn.lock
 | 
			
		||||
.DS_Store
 | 
			
		||||
/files
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										164
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										164
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -1,6 +1,170 @@
 | 
			
		||||
ChangeLog
 | 
			
		||||
=========
 | 
			
		||||
 | 
			
		||||
If you encounter any problems with updating, please try the following:
 | 
			
		||||
1. `npm run clean` or `npm run cleanall`
 | 
			
		||||
2. Retry update (Don't forget `npm i`)
 | 
			
		||||
 | 
			
		||||
10.102.1
 | 
			
		||||
----------
 | 
			
		||||
* 投稿が増殖する問題を修正
 | 
			
		||||
* リモートユーザーの修復処理が自動的に実行されない問題を修正
 | 
			
		||||
 | 
			
		||||
10.101.0
 | 
			
		||||
----------
 | 
			
		||||
* WebFingerリクエストで Proxy, Keep-Alive などをサポート
 | 
			
		||||
* AP actor Service のサポートが不完全な問題を修正
 | 
			
		||||
* Punycodeなインスタンスが重複登録される問題を修正
 | 
			
		||||
* ObjectStrage利用時にドライブファイルアイコンが表示されない問題を修正
 | 
			
		||||
 | 
			
		||||
10.100.0
 | 
			
		||||
----------
 | 
			
		||||
* ユーザーリストでフォローボタンを表示するように
 | 
			
		||||
* ドライブのファイルのサムネイルを修正
 | 
			
		||||
* 投稿ウィジットでローカルのみの公開範囲で投稿できない問題を修正
 | 
			
		||||
* TLを遡った時に抜けがある時がある問題を修正
 | 
			
		||||
* ユーザータイムラインが投稿日時順ではなくなっているのを修正
 | 
			
		||||
* 10.99.0 でチャートのレンダリングがおかしい問題を修正
 | 
			
		||||
 | 
			
		||||
10.99.0
 | 
			
		||||
----------
 | 
			
		||||
* manifest.json にインスタンス名を反映させるように
 | 
			
		||||
* Metaに投稿やユーザーのIDを設定するように
 | 
			
		||||
* 設定でポートが指定されていない場合、環境変数を参照するように
 | 
			
		||||
* フォローインポートで途中にエラーになるユーザーがいると途中で終了してしまう問題を修正
 | 
			
		||||
* フォローインポートで自分が含まれていた場合自分をフォローしてしまう問題を修正
 | 
			
		||||
* ServiceWorkerの設定がUIで有効にならない問題を修正
 | 
			
		||||
* ユーザー一覧でのユーザーの自己紹介が複数行になることがある問題を修正
 | 
			
		||||
* フォローインポートでAPI limitに達していても正常にリクエストされたように表示されてしまう問題を修正
 | 
			
		||||
* DBに保存されたrepository urlを変更する方法がない問題を修正
 | 
			
		||||
* デスクトップDeckだとviaが投稿内に2箇所表示される問題を修正
 | 
			
		||||
* デザインの調整
 | 
			
		||||
* 依存関係の更新
 | 
			
		||||
* ローカリゼーション
 | 
			
		||||
 | 
			
		||||
10.98.3
 | 
			
		||||
----------
 | 
			
		||||
* リアクションのカスタム絵文字の情報がNoteに添付されない問題を修正
 | 
			
		||||
* フォルダーの移動をするとき親フォルダーに自分自身を指定できてしまう問題を修正
 | 
			
		||||
* デザインの調整
 | 
			
		||||
 | 
			
		||||
10.98.2
 | 
			
		||||
----------
 | 
			
		||||
* 他のインスタンスから添付画像が見れない問題を修正
 | 
			
		||||
 | 
			
		||||
10.98.1
 | 
			
		||||
----------
 | 
			
		||||
* ドライブのファイルのサムネイルが表示されない問題を修正
 | 
			
		||||
* APでカスタム絵文字を送る時に常にimage/pngで送っている問題を修正
 | 
			
		||||
* いくらいじってもページリロードするとmisskeyのテーマがdark(future)になっちゃう問題を修正
 | 
			
		||||
 | 
			
		||||
10.98.0
 | 
			
		||||
----------
 | 
			
		||||
* ドライブのファイルダウンロード時に元のファイル名を尊重するように
 | 
			
		||||
* ドライブで画像以外のファイルを分かりやすく表示するように
 | 
			
		||||
* TwemojiのCDNを変更
 | 
			
		||||
* モバイルで通知の設定がない問題を修正
 | 
			
		||||
* デザインの調整
 | 
			
		||||
 | 
			
		||||
10.97.2
 | 
			
		||||
----------
 | 
			
		||||
* ビルド時に警告が出ないように修正
 | 
			
		||||
 | 
			
		||||
10.97.1
 | 
			
		||||
----------
 | 
			
		||||
* デザインの調整
 | 
			
		||||
 | 
			
		||||
10.97.0
 | 
			
		||||
----------
 | 
			
		||||
* リアクションに絵文字やカスタム絵文字を使えるように
 | 
			
		||||
* 不明なリアクションのフォールバックに star を使えるように
 | 
			
		||||
* デザインの調整
 | 
			
		||||
 | 
			
		||||
10.96.0
 | 
			
		||||
----------
 | 
			
		||||
* 連合ユーザーの投稿に対してActivityPubオブジェクトを要求されたら元のインスタンスにリダイレクトするように
 | 
			
		||||
* updatePersonを試行した時点でもlastFetchedAtを更新するように
 | 
			
		||||
* 管理画面でリモートインスタンスの登録日時を表示
 | 
			
		||||
* ユーザーサジェストが機能しなくなっていた問題を修正
 | 
			
		||||
* 最近使ったハッシュタグ表示が機能していない問題を修正
 | 
			
		||||
* バグ修正
 | 
			
		||||
* デザインの調整
 | 
			
		||||
 | 
			
		||||
10.95.0
 | 
			
		||||
----------
 | 
			
		||||
* ジョブを一覧できるように
 | 
			
		||||
* MFMでURLを明示する構文の追加
 | 
			
		||||
* Articleタイプのアクティビティを受け入れるように
 | 
			
		||||
* 凍結されたユーザーをサジェストしないように
 | 
			
		||||
* ファビコンが保存されないのを修正
 | 
			
		||||
* キューのジョブクリアの動作を修正
 | 
			
		||||
* デザインの調整
 | 
			
		||||
 | 
			
		||||
10.94.0
 | 
			
		||||
----------
 | 
			
		||||
* Faviconを設定できるように
 | 
			
		||||
* アカウントを凍結したときすべてのフォローを解除するように
 | 
			
		||||
* シェアページが機能していない問題を修正
 | 
			
		||||
* インスタンスブロックをしていてもRenote等すると取得されてしまう問題を修正
 | 
			
		||||
* デザインの調整
 | 
			
		||||
 | 
			
		||||
10.93.1
 | 
			
		||||
----------
 | 
			
		||||
* データのエクスポートとインポートの動作を修正
 | 
			
		||||
* デザインの調整
 | 
			
		||||
 | 
			
		||||
10.93.0
 | 
			
		||||
----------
 | 
			
		||||
* フォローリストをインポートできるように
 | 
			
		||||
* embedプレイヤーを閉じれるように
 | 
			
		||||
* リストをインポートしたときにプロキシアカウントがフォローするように修正
 | 
			
		||||
* Web Share Targetの動作を修正
 | 
			
		||||
* おすすめアンケートのチョイスを修正
 | 
			
		||||
* デザインの調整
 | 
			
		||||
 | 
			
		||||
10.92.4
 | 
			
		||||
----------
 | 
			
		||||
* リストのエクスポートをできるように
 | 
			
		||||
* ジョブキューウィジェットを追加
 | 
			
		||||
* URLプレビューのサムネイルが表示されないことがある問題を修正
 | 
			
		||||
 | 
			
		||||
10.92.3
 | 
			
		||||
----------
 | 
			
		||||
* 管理画面の各種ジョブ数がおかしい問題を修正
 | 
			
		||||
* ジョブキューの動作を調整
 | 
			
		||||
 | 
			
		||||
10.92.2
 | 
			
		||||
----------
 | 
			
		||||
* 管理画面で各種ジョブ数を一覧できるように
 | 
			
		||||
* ジョブキューの動作を修正
 | 
			
		||||
* notes/children が遅い問題を修正
 | 
			
		||||
 | 
			
		||||
10.92.1
 | 
			
		||||
----------
 | 
			
		||||
* アンケートの結果をリモートと同期するように
 | 
			
		||||
* ジョブキューを有効に
 | 
			
		||||
* 投稿の返信一覧に引用Renoteも含めるように
 | 
			
		||||
* robots.txt追加
 | 
			
		||||
* デザインの調整
 | 
			
		||||
 | 
			
		||||
10.92.0
 | 
			
		||||
----------
 | 
			
		||||
* Mastodonのアンケートに対応
 | 
			
		||||
* 複数回答できるアンケートを作成できるように
 | 
			
		||||
* アンケートに期限を設定できるように
 | 
			
		||||
* 絵文字ピッカーを改良
 | 
			
		||||
* ハッシュタグの判定を改善
 | 
			
		||||
* デッキのタグTLで別のタグをクリックしてもTLが変わらない問題を修正
 | 
			
		||||
* ユーザーサジェストで表示名が変わらない問題を修正
 | 
			
		||||
* UIのバグ修正
 | 
			
		||||
* デザインの調整
 | 
			
		||||
* など
 | 
			
		||||
 | 
			
		||||
10.91.2
 | 
			
		||||
----------
 | 
			
		||||
* 10.91.1 で追加した依存関係にXSS脆弱性があったので他のパッケージに差し替え
 | 
			
		||||
* 初期アクセスでテーマが正しく設定されない問題を修正
 | 
			
		||||
 | 
			
		||||
10.91.1
 | 
			
		||||
----------
 | 
			
		||||
* ログビューを強化
 | 
			
		||||
 
 | 
			
		||||
@@ -46,6 +46,9 @@ Convert な(na) to にゃ(nya)
 | 
			
		||||
Revert Nyaize
 | 
			
		||||
 | 
			
		||||
## Code style
 | 
			
		||||
### Use semicolon
 | 
			
		||||
To avoid ASI Hazard
 | 
			
		||||
 | 
			
		||||
### Don't use `export default`
 | 
			
		||||
Bad:
 | 
			
		||||
``` ts
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										81
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										81
									
								
								README.md
									
									
									
									
									
								
							@@ -1,4 +1,4 @@
 | 
			
		||||
<img src="https://github.com/syuilo/misskey/blob/develop/assets/ai-orig.png?raw=true" align="right" height="320px"/>
 | 
			
		||||
<a href="https://ai.misskey.xyz/"><img src="https://github.com/syuilo/misskey/blob/develop/assets/ai-orig.png?raw=true" align="right" height="320px"/></a>
 | 
			
		||||
 | 
			
		||||
[](https://misskey.xyz/)
 | 
			
		||||
================================================================
 | 
			
		||||
@@ -88,12 +88,14 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
 | 
			
		||||
		<td><img src="https://avatars0.githubusercontent.com/u/10798641?s=460&v=4" alt="AyaMorisawa" width="100"></td>
 | 
			
		||||
		<td><img src="https://avatars1.githubusercontent.com/u/30769358?s=460&v=4" alt="mei23" width="100"></td>
 | 
			
		||||
		<td><img src="https://avatars2.githubusercontent.com/u/20679825?s=460&v=4" alt="acid-chicken" width="100"></td>
 | 
			
		||||
		<td><img src="https://avatars2.githubusercontent.com/u/6533808?s=460&v=4" alt="rinsuki" width="100"></td>
 | 
			
		||||
	</tr>
 | 
			
		||||
	<tr>
 | 
			
		||||
		<td align="center"><a href="https://github.com/syuilo">@syuilo</a></td>
 | 
			
		||||
		<td align="center"><a href="https://github.com/AyaMorisawa">@AyaMorisawa</a></td>
 | 
			
		||||
		<td align="center"><a href="https://github.com/mei23">@mei23</a></td>
 | 
			
		||||
		<td align="center"><a href="https://github.com/acid-chicken">@acid-chicken</a></td>
 | 
			
		||||
		<td align="center"><a href="https://github.com/rinsuki">@rinsuki</a></td>
 | 
			
		||||
	</tr>
 | 
			
		||||
</table>
 | 
			
		||||
 | 
			
		||||
@@ -101,56 +103,83 @@ Please see the [Contribution Guide](./CONTRIBUTING.md).
 | 
			
		||||
----------------------------------------------------------------
 | 
			
		||||
<!-- PATREON_START -->
 | 
			
		||||
<table><tr>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12190916/fb7fa7983c14425f890369535b1506a4/1?token-time=2145916800&token-hash=WeuDzzz24cRXJogyIkU-mxARqkdyms-rcZKbO-GpGjw%3D" alt="weep" width="100"></td>
 | 
			
		||||
<td><img src="https://c8.patreon.com/2/200/12059069" alt="naga_rus" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12913507/f7181eacafe8469a93033d85f5969c29/3?token-time=2145916800&token-hash=c8HeVqLtmdgH-gSBJg8i10gmOcwllM87MDHeznl3el0%3D" alt="Melilot" width="100"></td>
 | 
			
		||||
<td><img src="https://c8.patreon.com/2/200/16869916" alt="見当かなみ" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12999811/5f349fafcce44dd1824a8b1ebbec4564/3?token-time=2145916800&token-hash=LtV2lRi3L2jOWMLwccr9qWYfPrFlzIo2jYZHKzHEb6k%3D" alt="Xeltica" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12021162/963128bb8d14476dbd8407943db8f31a/1?token-time=2145916800&token-hash=1FlxS9MEgmNGH_RHUVHbO5hIXB5I1z0lvA33CTvYvjA%3D" alt="gutfuckllc" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5888816/36da0f7c15954df0ab13f9abdf227f66/1.jpeg?token-time=2145916800&token-hash=at8QpJXJ8C0zINY_NmoMKv-MhXVoUK-YzTgaJPJzJYU%3D" alt="Hiroshi Seki" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12190916/fb7fa7983c14425f890369535b1506a4/3.png?token-time=2145916800&token-hash=oH_i7gJjNT7Ot6j9JiVwy7ZJIBqACVnzLqlz4YrDAZA%3D" alt="weepjp" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/19045173/cb91c0f345c24d4ebfd05f19906d5e26/1.png?token-time=2145916800&token-hash=o_zKBytJs_AxHwSYw_5R8eD0eSJe3RoTR3kR3Q0syN0%3D" alt="kiritan" width="100"></td>
 | 
			
		||||
<td><img src="https://c8.patreon.com/2/200/776209" alt="Denshi" width="100"></td>
 | 
			
		||||
<td><img src="https://c8.patreon.com/2/200/557245" alt="mkatze" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13099460/43cecdbaa63a40d79bf50a96b9910b9d/1.jpe?token-time=2145916800&token-hash=bqwLTk0Wo0hUJJ8J5y7ii05bLzz-_CDA7Bo0Mp4RFU0%3D" alt="ne_moni" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12913507/f7181eacafe8469a93033d85f5969c29/4.jpe?token-time=2145916800&token-hash=zEyJqVM7u9d8Ri-65fJYSJcWF1jBH1nJ5a3taRzrTmw%3D" alt="Melilot" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5670915/ee175f0bfb6347ffa4ea101a8c097bff/1.jpg?token-time=2145916800&token-hash=mPLM9CA-riFHx-myr3bLZJuH2xBRHA9se5VbHhLIOuA%3D" alt="osapon" width="100"></td>
 | 
			
		||||
</tr><tr>
 | 
			
		||||
<td><a href="https://www.patreon.com/weepjp">weep</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/user?u=12059069">naga_rus</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/rane_hs">Hiroshi Seki</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/weepjp">weepjp</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/user?u=19045173">kiritan</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/user?u=776209">Denshi</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/user?u=557245">mkatze</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>
 | 
			
		||||
<td><a href="https://www.patreon.com/user?u=16869916">見当かなみ</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/Xeltica">Xeltica</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/gutfuckllc">gutfuckllc</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/osapon">osapon</a></td>
 | 
			
		||||
</tr></table>
 | 
			
		||||
<table><tr>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/11357794/923ce94cd8c44ba788ee931907881839/1?token-time=2145916800&token-hash=0xgcpqvFDqRcV_YIEhcPNVH7gs9sLg_BBnTJXCkN4ao%3D" alt="mydarkstar" width="100"></td>
 | 
			
		||||
<td><img src="https://c8.patreon.com/2/200/16869916" alt="見当かなみ" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/18899730/6a22797f68254034a854d69ea2445fc8/1.png?token-time=2145916800&token-hash=b_uj57yxo5VzkSOUS7oXE_762dyOTB_oxzbO6lFNG3k%3D" alt="YuzuRyo61" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12021162/963128bb8d14476dbd8407943db8f31a/1.png?token-time=2145916800&token-hash=FMV7cPKBD1TU2WTbl1jg6AcdKSvTb2BSFcDhgc-EO8w%3D" alt="gutfuckllc" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/11357794/923ce94cd8c44ba788ee931907881839/1.png?token-time=2145916800&token-hash=9nEQje_eMvUjq9a7L3uBqW-MQbS-rRMaMgd7UYVoFNM%3D" alt="mydarkstar" width="100"></td>
 | 
			
		||||
<td><img src="https://c8.patreon.com/2/200/12718187" alt="Peter G." width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13039004/509d0c412eb14ae08d6a812a3054f7d6/1?token-time=2145916800&token-hash=2PsbFNw0tnubZzgSXD01R6hIgncfiElG7H7HX2Y3dyo%3D" alt="nemu" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13039004/509d0c412eb14ae08d6a812a3054f7d6/1.jpe?token-time=2145916800&token-hash=UQRWf01TwHDV4Cls1K0YAOAjM29ssif7hLVq0ESQ0hs%3D" alt="nemu" width="100"></td>
 | 
			
		||||
<td><img src="https://c8.patreon.com/2/200/17866454" alt="sikyosyounin" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5881381/6235ca5d3fb04c8e95ef5b4ff2abcc18/3?token-time=2145916800&token-hash=9JtETp0X8gI280Ne1E8bxn6j4Lw5o2k4mJkICx97V_k%3D" alt="YUKIMOCHI" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5881381/6235ca5d3fb04c8e95ef5b4ff2abcc18/3.png?token-time=2145916800&token-hash=KjfQL8nf3AIf6WqzLshBYAyX44piAqOAZiYXgZS_H6A%3D" alt="YUKIMOCHI" width="100"></td>
 | 
			
		||||
<td><img src="https://c8.patreon.com/2/200/17463605" alt="Sampot" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/17880724/311738c8a48f4a6b9443c2445a75adde/1?token-time=2145916800&token-hash=95p8VdGX45E8BitZR_eOcDlqCjumjzNLBPQJrJdeCpI%3D" alt="takimura" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/17195955/be45e5e14c3e48b2bee0456c84e19df4/4?token-time=2145916800&token-hash=SbdZeN5SmsuT9stD6v0jN1z0hftg0FmRiCTxysU0Ihw%3D" alt="Damillora" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/19356899/496b4681d33b4520bd7688e0fd19c04d/2.jpeg?token-time=2145916800&token-hash=_sTj3dUBOhn9qwiJ7F19Qd-yWWfUqJC_0jG1h0agEqQ%3D" alt="sheeta.s" width="100"></td>
 | 
			
		||||
</tr><tr>
 | 
			
		||||
<td><a href="https://www.patreon.com/user?u=16869916">見当かなみ</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/Yuzulia">YuzuRyo61</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/gutfuckllc">gutfuckllc</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/mydarkstar">mydarkstar</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/user?u=12718187">Peter G.</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/user?u=13039004">nemu</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/user?u=17866454">sikyosyounin</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/yukimochi">YUKIMOCHI</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/user?u=17463605">Sampot</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/takimura">takimura</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/damillora">Damillora</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/user?u=19356899">sheeta.s</a></td>
 | 
			
		||||
</tr></table>
 | 
			
		||||
<table><tr>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/4389829/9f709180ac714651a70f74a82f3ffdb9/2?token-time=2145916800&token-hash=zcwFxb2zopzWwksKVU1YpfAEjsl4yKT02aQ6yiAFRiQ%3D" alt="natalie" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13034746/c711c7f58e204ecfbc2fd646bc8a4eee/1?token-time=2145916800&token-hash=5T8XcaAf9Zyzfg3QubR06s_kJZkArVEM2dwObrBVAU4%3D" alt="Hiratake" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/4503830/ccf2cc867ea64de0b524bb2e24b9a1cb/1?token-time=2145916800&token-hash=Ksk_2l3gjPDbnzMUOCSW1E-hdPJsNs2tSR4_RAakRK8%3D" alt="dansup" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/619786/32cf01444db24e578cd1982c197f6fc6/1?token-time=2145916800&token-hash=CXe9AqlZy9AsYfiWd3OBYVOzvODoN47Litz0Tu4BFpU%3D" alt="Gargron" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5731881/4b6038e6cda34c04b83a5fcce3806a93/1?token-time=2145916800&token-hash=xhR1n6NAAyEb-IUXLD6_dshkFa3mefU5ZZuk1L8qKTs%3D" alt="Nokotaro Takeda" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12531784/93a45137841849329ba692da92ac7c60/1?token-time=2145916800&token-hash=uR-48MQ0A4j0irQSrCAQZJ-sJUSs_Fkihlg3-l59b7c%3D" alt="Takashi Shibuya" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13737140/1adf7835017d479280d90fe8d30aade2/1.png?token-time=2145916800&token-hash=0pdle8h5pDZrww0BDOjdz6zO-HudeGTh36a3qi1biVU%3D" alt="Satsuki Yanagi" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/17880724/311738c8a48f4a6b9443c2445a75adde/1.jpe?token-time=2145916800&token-hash=CPxGQhKIlEaa6WUcgbyHixyKEhakiw9RFdOhsIJBQ_o%3D" alt="takimura" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/17195955/be45e5e14c3e48b2bee0456c84e19df4/4.jpe?token-time=2145916800&token-hash=UslrPVM-8TXOe8AapuNiaFYjcIJgPNcU-fKpGbfGJNI%3D" alt="Damillora" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/16900731/83884b38afc74d4cbe83c30a13b10edd/1.png?token-time=2145916800&token-hash=R5Tog8RWg0rguRoCIoir3lThokrdPvs8Utfikhc0nhY%3D" alt="Atsuko Tominaga" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/4389829/9f709180ac714651a70f74a82f3ffdb9/3.png?token-time=2145916800&token-hash=FTm3WVom4dJ9NwWMU4OpCL_8Yc13WiwEbKrDPyTZTPs%3D" alt="natalie" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/13034746/c711c7f58e204ecfbc2fd646bc8a4eee/1.jpe?token-time=2145916800&token-hash=EWxXhVbZYH7KB4IDT3joc8TbIg8zPO40x1r5IDn3R7c%3D" alt="Hiratake" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5923936/2a743cbfbff946c2af3f09026047c0da/2.png?token-time=2145916800&token-hash=h6yphW1qnM0n_NOWaf8qtszMRLXEwIxfk5beu4RxdT0%3D" alt="noellabo" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/2384390/5681180e1efb46a8b28e0e8d4c8b9037/1.jpg?token-time=2145916800&token-hash=SJcMy-Q1BcS940-LFUVOMfR7-5SgrzsEQGhYb3yowFk%3D" alt="CG" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/18072312/98e894d960314fa7bc236a72a39488fe/1.jpe?token-time=2145916800&token-hash=qA8j97lIZNc-74AuZ0p4F3ms6sKPeKjtNt2vEuwpsyo%3D" alt="Hekovic" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/10789744/97175095d8f04c0f86225ff47cb98d40/1.jpeg?token-time=2145916800&token-hash=l4AoMR7Nj7K4yAHrkrk2hAoggPkbSPm12m1nmbe9Pb8%3D" alt="Naoki Hirayama" width="100"></td>
 | 
			
		||||
</tr><tr>
 | 
			
		||||
<td><a href="https://www.patreon.com/user?u=13737140">Satsuki Yanagi</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/takimura">takimura</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/damillora">Damillora</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/user?u=16900731">Atsuko Tominaga</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/user?u=4389829">natalie</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/hiratake">Hiratake</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/noellabo">noellabo</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/Corset">CG</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/hekovic">Hekovic</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/spinlock">Naoki Hirayama</a></td>
 | 
			
		||||
</tr></table>
 | 
			
		||||
<table><tr>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/4503830/ccf2cc867ea64de0b524bb2e24b9a1cb/1.jpeg?token-time=2145916800&token-hash=L55UhJ0rcuNAH3w_ryeeGN4hC6taoOixyAhraEi0bzw%3D" alt="dansup" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/619786/32cf01444db24e578cd1982c197f6fc6/1.jpeg?token-time=2145916800&token-hash=d8jBQLMOHD87KtXs5C9fk1o58DMF73pQ-dYH3uZJPBE%3D" alt="Gargron" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/5731881/4b6038e6cda34c04b83a5fcce3806a93/1.png?token-time=2145916800&token-hash=hBayGfOmQH3kRMdNnDe4oCZD_9fsJWSt29xXR3KRMVk%3D" alt="Nokotaro Takeda" width="100"></td>
 | 
			
		||||
<td><img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12531784/93a45137841849329ba692da92ac7c60/1.jpeg?token-time=2145916800&token-hash=vGe7wXGqmA8Q7m-kDNb6fyGdwk-Dxk4F-ut8ZZu51RM%3D" alt="Takashi Shibuya" width="100"></td>
 | 
			
		||||
</tr><tr>
 | 
			
		||||
<td><a href="https://www.patreon.com/dansup">dansup</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/mastodon">Gargron</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/takenoko">Nokotaro Takeda</a></td>
 | 
			
		||||
<td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td>
 | 
			
		||||
</tr></table>
 | 
			
		||||
 | 
			
		||||
**Last updated:** Fri, 01 Mar 2019 23:59:07 UTC
 | 
			
		||||
**Last updated:** Mon, 03 Jun 2019 17:28:09 UTC
 | 
			
		||||
<!-- PATREON_END -->
 | 
			
		||||
 | 
			
		||||
:four_leaf_clover: Copyright
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								assets/robots.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								assets/robots.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
user-agent: *
 | 
			
		||||
allow: /
 | 
			
		||||
 | 
			
		||||
# todo: sitemap
 | 
			
		||||
@@ -9,9 +9,23 @@ This guide describes how to install and setup Misskey with Docker.
 | 
			
		||||
 | 
			
		||||
*1.* Download Misskey
 | 
			
		||||
----------------------------------------------------------------
 | 
			
		||||
1. `git clone -b master git://github.com/syuilo/misskey.git` Clone Misskey repository's master branch.
 | 
			
		||||
2. `cd misskey` Move to misskey directory.
 | 
			
		||||
3. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` Checkout to the [latest release](https://github.com/syuilo/misskey/releases/latest) tag.
 | 
			
		||||
1. Clone Misskey repository's master branch.
 | 
			
		||||
 | 
			
		||||
	`git clone -b master git://github.com/syuilo/misskey.git`
 | 
			
		||||
 | 
			
		||||
2. Move to misskey directory.
 | 
			
		||||
 | 
			
		||||
	`cd misskey`
 | 
			
		||||
 | 
			
		||||
3. Checkout to the [latest release](https://github.com/syuilo/misskey/releases/latest) tag.
 | 
			
		||||
 | 
			
		||||
	```bash
 | 
			
		||||
	git tag | grep '^10\.' | sort -V --reverse | \
 | 
			
		||||
	while read tag_name; do \
 | 
			
		||||
	if ! curl -s "https://api.github.com/repos/syuilo/misskey/releases/tags/$tag_name" \
 | 
			
		||||
	| grep -qE '"(draft|prerelease)": true'; \
 | 
			
		||||
	then git checkout $tag_name; break; fi ; done
 | 
			
		||||
	```
 | 
			
		||||
 | 
			
		||||
*2.* Configure Misskey
 | 
			
		||||
----------------------------------------------------------------
 | 
			
		||||
@@ -39,7 +53,15 @@ Just `docker-compose up -d`. GLHF!
 | 
			
		||||
### How to update your Misskey server to the latest version
 | 
			
		||||
1. `git fetch`
 | 
			
		||||
2. `git stash`
 | 
			
		||||
3. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)`
 | 
			
		||||
3. 
 | 
			
		||||
 | 
			
		||||
	```bash
 | 
			
		||||
	git tag | grep '^10\.' | sort -V --reverse | \
 | 
			
		||||
	while read tag_name; do \
 | 
			
		||||
	if ! curl -s "https://api.github.com/repos/syuilo/misskey/releases/tags/$tag_name" \
 | 
			
		||||
	| grep -qE '"(draft|prerelease)": true'; \
 | 
			
		||||
	then git checkout $tag_name; break; fi ; done
 | 
			
		||||
	```
 | 
			
		||||
4. `git stash pop`
 | 
			
		||||
5. `docker-compose build`
 | 
			
		||||
6. Check [ChangeLog](../CHANGELOG.md) for migration information
 | 
			
		||||
 
 | 
			
		||||
@@ -10,9 +10,23 @@ Ce guide explique comment installer et configurer Misskey avec Docker.
 | 
			
		||||
 | 
			
		||||
*1.* Télécharger Misskey
 | 
			
		||||
----------------------------------------------------------------
 | 
			
		||||
1. `git clone -b master git://github.com/syuilo/misskey.git` Clone le dépôt de Misskey sur la branche master.
 | 
			
		||||
2. `cd misskey` Naviguez dans le dossier du dépôt.
 | 
			
		||||
3. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` Checkout sur le tag de la [dernière version](https://github.com/syuilo/misskey/releases/latest).
 | 
			
		||||
1. Clone le dépôt de Misskey sur la branche master.
 | 
			
		||||
 | 
			
		||||
	`git clone -b master git://github.com/syuilo/misskey.git`
 | 
			
		||||
 | 
			
		||||
2. Naviguez dans le dossier du dépôt.
 | 
			
		||||
 | 
			
		||||
	`cd misskey`
 | 
			
		||||
 | 
			
		||||
3. Checkout sur le tag de la [dernière version](https://github.com/syuilo/misskey/releases/latest).
 | 
			
		||||
 | 
			
		||||
	```bash
 | 
			
		||||
	git tag | grep '^10\.' | sort -V --reverse | \
 | 
			
		||||
	while read tag_name; do \
 | 
			
		||||
	if ! curl -s "https://api.github.com/repos/syuilo/misskey/releases/tags/$tag_name" \
 | 
			
		||||
	| grep -qE '"(draft|prerelease)": true'; \
 | 
			
		||||
	then git checkout $tag_name; break; fi ; done
 | 
			
		||||
	```
 | 
			
		||||
 | 
			
		||||
*2.* Configuration de Misskey
 | 
			
		||||
----------------------------------------------------------------
 | 
			
		||||
@@ -40,7 +54,15 @@ Utilisez la commande `docker-compose up -d`. GLHF!
 | 
			
		||||
### How to update your Misskey server to the latest version
 | 
			
		||||
1. `git fetch`
 | 
			
		||||
2. `git stash`
 | 
			
		||||
3. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)`
 | 
			
		||||
3. 
 | 
			
		||||
 | 
			
		||||
	```bash
 | 
			
		||||
	git tag | grep '^10\.' | sort -V --reverse | \
 | 
			
		||||
	while read tag_name; do \
 | 
			
		||||
	if ! curl -s "https://api.github.com/repos/syuilo/misskey/releases/tags/$tag_name" \
 | 
			
		||||
	| grep -qE '"(draft|prerelease)": true'; \
 | 
			
		||||
	then git checkout $tag_name; break; fi ; done
 | 
			
		||||
	```
 | 
			
		||||
4. `git stash pop`
 | 
			
		||||
5. `docker-compose build`
 | 
			
		||||
6. Consultez le [ChangeLog](../CHANGELOG.md) pour avoir les éventuelles informations de migration
 | 
			
		||||
@@ -52,14 +74,28 @@ Utilisez la commande `docker-compose up -d`. GLHF!
 | 
			
		||||
### Configuration d'ElasticSearch (pour la fonction de recherche)
 | 
			
		||||
*1.* Préparation de l'environnement
 | 
			
		||||
----------------------------------------------------------------
 | 
			
		||||
1. `mkdir elasticsearch && chown 1000:1000 elasticsearch` Permet de créer le dossier d'accueil de la base ElasticSearch aves les bons droits
 | 
			
		||||
2. `sysctl -w vm.max_map_count=262144` Augmente la valeur max du paramètre map_count du système (valeur minimum pour pouvoir lancer ES)
 | 
			
		||||
1. Permet de créer le dossier d'accueil de la base ElasticSearch aves les bons droits
 | 
			
		||||
 | 
			
		||||
	`mkdir elasticsearch && chown 1000:1000 elasticsearch`
 | 
			
		||||
 | 
			
		||||
2. Augmente la valeur max du paramètre map_count du système (valeur minimum pour pouvoir lancer ES)
 | 
			
		||||
 | 
			
		||||
	`sysctl -w vm.max_map_count=262144`
 | 
			
		||||
 | 
			
		||||
*2.* Après lancement du docker-compose, initialisation de la base ElasticSearch
 | 
			
		||||
----------------------------------------------------------------
 | 
			
		||||
1. `docker-compose -it web /bin/sh` Connexion dans le conteneur web
 | 
			
		||||
2. `apk add curl` Ajout du paquet curl
 | 
			
		||||
3. `curl -X PUT "es:9200/misskey" -H 'Content-Type: application/json' -d'{ "settings" : { "index" : { } }}'` Création de la base ES
 | 
			
		||||
1. Connexion dans le conteneur web
 | 
			
		||||
 | 
			
		||||
	`docker-compose -it web /bin/sh`
 | 
			
		||||
 | 
			
		||||
2. Ajout du paquet curl
 | 
			
		||||
 | 
			
		||||
	`apk add curl`
 | 
			
		||||
 | 
			
		||||
3. Création de la base ES
 | 
			
		||||
 | 
			
		||||
	`curl -X PUT "es:9200/misskey" -H 'Content-Type: application/json' -d'{ "settings" : { "index" : { } }}'`
 | 
			
		||||
 | 
			
		||||
4. `exit`
 | 
			
		||||
 | 
			
		||||
----------------------------------------------------------------
 | 
			
		||||
 
 | 
			
		||||
@@ -9,9 +9,23 @@ Dockerを使ったMisskey構築方法
 | 
			
		||||
 | 
			
		||||
*1.* Misskeyのダウンロード
 | 
			
		||||
----------------------------------------------------------------
 | 
			
		||||
1. `git clone -b master git://github.com/syuilo/misskey.git` masterブランチからMisskeyレポジトリをクローン
 | 
			
		||||
2. `cd misskey` misskeyディレクトリに移動
 | 
			
		||||
3. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` [最新のリリース](https://github.com/syuilo/misskey/releases/latest)を確認
 | 
			
		||||
1. masterブランチからMisskeyレポジトリをクローン
 | 
			
		||||
 | 
			
		||||
	`git clone -b master git://github.com/syuilo/misskey.git`
 | 
			
		||||
 | 
			
		||||
2. misskeyディレクトリに移動
 | 
			
		||||
 | 
			
		||||
	`cd misskey`
 | 
			
		||||
 | 
			
		||||
3. [最新のリリース](https://github.com/syuilo/misskey/releases/latest)を確認
 | 
			
		||||
 | 
			
		||||
	```bash
 | 
			
		||||
	git tag | grep '^10\.' | sort -V --reverse | \
 | 
			
		||||
	while read tag_name; do \
 | 
			
		||||
	if ! curl -s "https://api.github.com/repos/syuilo/misskey/releases/tags/$tag_name" \
 | 
			
		||||
	| grep -qE '"(draft|prerelease)": true'; \
 | 
			
		||||
	then git checkout $tag_name; break; fi ; done
 | 
			
		||||
	```
 | 
			
		||||
 | 
			
		||||
*2.* 設定ファイルを作成する
 | 
			
		||||
----------------------------------------------------------------
 | 
			
		||||
@@ -39,7 +53,15 @@ Dockerを使ったMisskey構築方法
 | 
			
		||||
### Misskeyを最新バージョンにアップデートする方法:
 | 
			
		||||
1. `git fetch`
 | 
			
		||||
2. `git stash`
 | 
			
		||||
3. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)`
 | 
			
		||||
3. 
 | 
			
		||||
 | 
			
		||||
	```bash
 | 
			
		||||
	git tag | grep '^10\.' | sort -V --reverse | \
 | 
			
		||||
	while read tag_name; do \
 | 
			
		||||
	if ! curl -s "https://api.github.com/repos/syuilo/misskey/releases/tags/$tag_name" \
 | 
			
		||||
	| grep -qE '"(draft|prerelease)": true'; \
 | 
			
		||||
	then git checkout $tag_name; break; fi ; done
 | 
			
		||||
	```
 | 
			
		||||
4. `git stash pop`
 | 
			
		||||
5. `docker-compose build`
 | 
			
		||||
6. [ChangeLog](../CHANGELOG.md)でマイグレーション情報を確認する
 | 
			
		||||
 
 | 
			
		||||
@@ -41,15 +41,38 @@ As root:
 | 
			
		||||
 | 
			
		||||
*4.* Install Misskey
 | 
			
		||||
----------------------------------------------------------------
 | 
			
		||||
1. `su - misskey` Connect to misskey user.
 | 
			
		||||
2. `git clone -b master git://github.com/syuilo/misskey.git` Clone the misskey repo from master branch.
 | 
			
		||||
3. `cd misskey` Navigate to misskey directory
 | 
			
		||||
4. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` Checkout to the [latest release](https://github.com/syuilo/misskey/releases/latest)
 | 
			
		||||
5. `npm install` Install misskey dependencies.
 | 
			
		||||
1. Connect to misskey user.
 | 
			
		||||
 | 
			
		||||
	`su - misskey`
 | 
			
		||||
 | 
			
		||||
2. Clone the misskey repo from master branch.
 | 
			
		||||
 | 
			
		||||
	`git clone -b master git://github.com/syuilo/misskey.git`
 | 
			
		||||
 | 
			
		||||
3. Navigate to misskey directory
 | 
			
		||||
 | 
			
		||||
	`cd misskey`
 | 
			
		||||
 | 
			
		||||
4. Checkout to the [latest release](https://github.com/syuilo/misskey/releases/latest)
 | 
			
		||||
 | 
			
		||||
	```bash
 | 
			
		||||
	git tag | grep '^10\.' | sort -V --reverse | \
 | 
			
		||||
	while read tag_name; do \
 | 
			
		||||
	if ! curl -s "https://api.github.com/repos/syuilo/misskey/releases/tags/$tag_name" \
 | 
			
		||||
	| grep -qE '"(draft|prerelease)": true'; \
 | 
			
		||||
	then git checkout $tag_name; break; fi ; done
 | 
			
		||||
	```
 | 
			
		||||
 | 
			
		||||
5. Install misskey dependencies.
 | 
			
		||||
 | 
			
		||||
	`npm install`
 | 
			
		||||
 | 
			
		||||
*5.* Configure Misskey
 | 
			
		||||
----------------------------------------------------------------
 | 
			
		||||
1. `cp .config/example.yml .config/default.yml` Copy the `.config/example.yml` and rename it to `default.yml`.
 | 
			
		||||
1. Copy the `.config/example.yml` and rename it to `default.yml`.
 | 
			
		||||
 | 
			
		||||
	`cp .config/example.yml .config/default.yml`
 | 
			
		||||
 | 
			
		||||
2. Edit `default.yml`
 | 
			
		||||
 | 
			
		||||
*6.* Build Misskey
 | 
			
		||||
@@ -77,37 +100,53 @@ Just `NODE_ENV=production npm start`. GLHF!
 | 
			
		||||
 | 
			
		||||
### Launch with systemd
 | 
			
		||||
 | 
			
		||||
1. Create a systemd service here: `/etc/systemd/system/misskey.service`
 | 
			
		||||
1. Create a systemd service here
 | 
			
		||||
 | 
			
		||||
	`/etc/systemd/system/misskey.service`
 | 
			
		||||
 | 
			
		||||
2. Edit it, and paste this and save:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
[Unit]
 | 
			
		||||
Description=Misskey daemon
 | 
			
		||||
	```
 | 
			
		||||
	[Unit]
 | 
			
		||||
	Description=Misskey daemon
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
Type=simple
 | 
			
		||||
User=misskey
 | 
			
		||||
ExecStart=/usr/bin/npm start
 | 
			
		||||
WorkingDirectory=/home/misskey/misskey
 | 
			
		||||
Environment="NODE_ENV=production"
 | 
			
		||||
TimeoutSec=60
 | 
			
		||||
StandardOutput=syslog
 | 
			
		||||
StandardError=syslog
 | 
			
		||||
SyslogIdentifier=misskey
 | 
			
		||||
Restart=always
 | 
			
		||||
	[Service]
 | 
			
		||||
	Type=simple
 | 
			
		||||
	User=misskey
 | 
			
		||||
	ExecStart=/usr/bin/npm start
 | 
			
		||||
	WorkingDirectory=/home/misskey/misskey
 | 
			
		||||
	Environment="NODE_ENV=production"
 | 
			
		||||
	TimeoutSec=60
 | 
			
		||||
	StandardOutput=syslog
 | 
			
		||||
	StandardError=syslog
 | 
			
		||||
	SyslogIdentifier=misskey
 | 
			
		||||
	Restart=always
 | 
			
		||||
 | 
			
		||||
[Install]
 | 
			
		||||
WantedBy=multi-user.target
 | 
			
		||||
```
 | 
			
		||||
	[Install]
 | 
			
		||||
	WantedBy=multi-user.target
 | 
			
		||||
	```
 | 
			
		||||
 | 
			
		||||
3. `systemctl daemon-reload ; systemctl enable misskey` Reload systemd and enable the misskey service.
 | 
			
		||||
4. `systemctl start misskey` Start the misskey service.
 | 
			
		||||
3. Reload systemd and enable the misskey service.
 | 
			
		||||
 | 
			
		||||
	`systemctl daemon-reload ; systemctl enable misskey`
 | 
			
		||||
 | 
			
		||||
4. Start the misskey service.
 | 
			
		||||
 | 
			
		||||
	`systemctl start misskey`
 | 
			
		||||
 | 
			
		||||
You can check if the service is running with `systemctl status misskey`.
 | 
			
		||||
 | 
			
		||||
### How to update your Misskey server to the latest version
 | 
			
		||||
1. `git fetch`
 | 
			
		||||
2. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)`
 | 
			
		||||
2.  
 | 
			
		||||
 | 
			
		||||
	```bash
 | 
			
		||||
	git tag | grep '^10\.' | sort -V --reverse | \
 | 
			
		||||
	while read tag_name; do \
 | 
			
		||||
	if ! curl -s "https://api.github.com/repos/syuilo/misskey/releases/tags/$tag_name" \
 | 
			
		||||
	| grep -qE '"(draft|prerelease)": true'; \
 | 
			
		||||
	then git checkout $tag_name; break; fi ; done
 | 
			
		||||
	```
 | 
			
		||||
3. `npm install`
 | 
			
		||||
4. `NODE_ENV=production npm run build`
 | 
			
		||||
5. Check [ChangeLog](../CHANGELOG.md) for migration information
 | 
			
		||||
 
 | 
			
		||||
@@ -41,15 +41,38 @@ En root :
 | 
			
		||||
 | 
			
		||||
*4.* Installation de Misskey
 | 
			
		||||
----------------------------------------------------------------
 | 
			
		||||
1. `su - misskey` Basculez vers l'utilisateur misskey.
 | 
			
		||||
2. `git clone -b master git://github.com/syuilo/misskey.git` Clonez la branche master du dépôt misskey.
 | 
			
		||||
3. `cd misskey` Accédez au dossier misskey.
 | 
			
		||||
4. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` Checkout sur le tag de la [version la plus récente](https://github.com/syuilo/misskey/releases/latest)
 | 
			
		||||
5. `npm install` Installez les dépendances de misskey.
 | 
			
		||||
1. Basculez vers l'utilisateur misskey.
 | 
			
		||||
 | 
			
		||||
	`su - misskey`
 | 
			
		||||
 | 
			
		||||
2. Clonez la branche master du dépôt misskey.
 | 
			
		||||
 | 
			
		||||
	`git clone -b master git://github.com/syuilo/misskey.git`
 | 
			
		||||
 | 
			
		||||
3. Accédez au dossier misskey.
 | 
			
		||||
 | 
			
		||||
	`cd misskey`
 | 
			
		||||
 | 
			
		||||
4. Checkout sur le tag de la [version la plus récente](https://github.com/syuilo/misskey/releases/latest)
 | 
			
		||||
 | 
			
		||||
	```bash
 | 
			
		||||
	git tag | grep '^10\.' | sort -V --reverse | \
 | 
			
		||||
	while read tag_name; do \
 | 
			
		||||
	if ! curl -s "https://api.github.com/repos/syuilo/misskey/releases/tags/$tag_name" \
 | 
			
		||||
	| grep -qE '"(draft|prerelease)": true'; \
 | 
			
		||||
	then git checkout $tag_name; break; fi ; done
 | 
			
		||||
	```
 | 
			
		||||
 
 | 
			
		||||
5. Installez les dépendances de misskey.
 | 
			
		||||
 | 
			
		||||
	`npm install`
 | 
			
		||||
 | 
			
		||||
*5.* Création du fichier de configuration
 | 
			
		||||
----------------------------------------------------------------
 | 
			
		||||
1. `cp .config/example.yml .config/default.yml` Copiez le fichier `.config/example.yml` et renommez-le`default.yml`.
 | 
			
		||||
1. Copiez le fichier `.config/example.yml` et renommez-le`default.yml`.
 | 
			
		||||
 | 
			
		||||
	`cp .config/example.yml .config/default.yml`
 | 
			
		||||
 | 
			
		||||
2. Editez le fichier `default.yml`
 | 
			
		||||
 | 
			
		||||
*6.* Construction de Misskey
 | 
			
		||||
@@ -77,37 +100,53 @@ Lancez tout simplement `NODE_ENV=production npm start`. Bonne chance et amusez-v
 | 
			
		||||
 | 
			
		||||
### Démarrage avec systemd
 | 
			
		||||
 | 
			
		||||
1. Créez un service systemd sur : `/etc/systemd/system/misskey.service`
 | 
			
		||||
1. Créez un service systemd sur
 | 
			
		||||
 | 
			
		||||
	`/etc/systemd/system/misskey.service`
 | 
			
		||||
 | 
			
		||||
2. Editez-le puis copiez et coller ceci dans le fichier :
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
[Unit]
 | 
			
		||||
Description=Misskey daemon
 | 
			
		||||
	```
 | 
			
		||||
	[Unit]
 | 
			
		||||
	Description=Misskey daemon
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
Type=simple
 | 
			
		||||
User=misskey
 | 
			
		||||
ExecStart=/usr/bin/npm start
 | 
			
		||||
WorkingDirectory=/home/misskey/misskey
 | 
			
		||||
Environment="NODE_ENV=production"
 | 
			
		||||
TimeoutSec=60
 | 
			
		||||
StandardOutput=syslog
 | 
			
		||||
StandardError=syslog
 | 
			
		||||
SyslogIdentifier=misskey
 | 
			
		||||
Restart=always
 | 
			
		||||
	[Service]
 | 
			
		||||
	Type=simple
 | 
			
		||||
	User=misskey
 | 
			
		||||
	ExecStart=/usr/bin/npm start
 | 
			
		||||
	WorkingDirectory=/home/misskey/misskey
 | 
			
		||||
	Environment="NODE_ENV=production"
 | 
			
		||||
	TimeoutSec=60
 | 
			
		||||
	StandardOutput=syslog
 | 
			
		||||
	StandardError=syslog
 | 
			
		||||
	SyslogIdentifier=misskey
 | 
			
		||||
	Restart=always
 | 
			
		||||
 | 
			
		||||
[Install]
 | 
			
		||||
WantedBy=multi-user.target
 | 
			
		||||
```
 | 
			
		||||
	[Install]
 | 
			
		||||
	WantedBy=multi-user.target
 | 
			
		||||
	```
 | 
			
		||||
 | 
			
		||||
3. `systemctl daemon-reload ; systemctl enable misskey` Redémarre systemd et active le service misskey.
 | 
			
		||||
4. `systemctl start misskey` Démarre le service misskey.
 | 
			
		||||
3. Redémarre systemd et active le service misskey.
 | 
			
		||||
 | 
			
		||||
	`systemctl daemon-reload ; systemctl enable misskey`
 | 
			
		||||
 | 
			
		||||
4. Démarre le service misskey.
 | 
			
		||||
 | 
			
		||||
	`systemctl start misskey`
 | 
			
		||||
 | 
			
		||||
Vous pouvez vérifier si le service a démarré en utilisant la commande `systemctl status misskey`.
 | 
			
		||||
 | 
			
		||||
### Méthode de mise à jour vers la plus récente version de Misskey
 | 
			
		||||
1. `git fetch`
 | 
			
		||||
2. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)`
 | 
			
		||||
2.  
 | 
			
		||||
 | 
			
		||||
	```bash
 | 
			
		||||
	git tag | grep '^10\.' | sort -V --reverse | \
 | 
			
		||||
	while read tag_name; do \
 | 
			
		||||
	if ! curl -s "https://api.github.com/repos/syuilo/misskey/releases/tags/$tag_name" \
 | 
			
		||||
	| grep -qE '"(draft|prerelease)": true'; \
 | 
			
		||||
	then git checkout $tag_name; break; fi ; done
 | 
			
		||||
	```
 | 
			
		||||
3. `npm install`
 | 
			
		||||
4. `NODE_ENV=production npm run build`
 | 
			
		||||
5. Consultez [ChangeLog](../CHANGELOG.md) pour les information de migration.
 | 
			
		||||
 
 | 
			
		||||
@@ -48,15 +48,38 @@ adduser --disabled-password --disabled-login misskey
 | 
			
		||||
 | 
			
		||||
*4.* Misskeyのインストール
 | 
			
		||||
----------------------------------------------------------------
 | 
			
		||||
1. `su - misskey` misskeyユーザーを使用
 | 
			
		||||
2. `git clone -b master git://github.com/syuilo/misskey.git` masterブランチからMisskeyレポジトリをクローン
 | 
			
		||||
3. `cd misskey` misskeyディレクトリに移動
 | 
			
		||||
4. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)` [最新のリリース](https://github.com/syuilo/misskey/releases/latest)を確認
 | 
			
		||||
5. `npm install` Misskeyの依存パッケージをインストール
 | 
			
		||||
1. misskeyユーザーを使用
 | 
			
		||||
 | 
			
		||||
	`su - misskey`
 | 
			
		||||
 | 
			
		||||
2. masterブランチからMisskeyレポジトリをクローン
 | 
			
		||||
 | 
			
		||||
	`git clone -b master git://github.com/syuilo/misskey.git`
 | 
			
		||||
 | 
			
		||||
3. misskeyディレクトリに移動
 | 
			
		||||
 | 
			
		||||
	`cd misskey`
 | 
			
		||||
 | 
			
		||||
4. [最新のリリース](https://github.com/syuilo/misskey/releases/latest)を確認
 | 
			
		||||
 | 
			
		||||
	```bash
 | 
			
		||||
	git tag | grep '^10\.' | sort -V --reverse | \
 | 
			
		||||
	while read tag_name; do \
 | 
			
		||||
	if ! curl -s "https://api.github.com/repos/syuilo/misskey/releases/tags/$tag_name" \
 | 
			
		||||
	| grep -qE '"(draft|prerelease)": true'; \
 | 
			
		||||
	then git checkout $tag_name; break; fi ; done
 | 
			
		||||
	```
 | 
			
		||||
 | 
			
		||||
5. Misskeyの依存パッケージをインストール
 | 
			
		||||
 | 
			
		||||
	`npm install`
 | 
			
		||||
 | 
			
		||||
*5.* 設定ファイルを作成する
 | 
			
		||||
----------------------------------------------------------------
 | 
			
		||||
1. `cp .config/example.yml .config/default.yml` `.config/example.yml`をコピーし名前を`default.yml`にする。
 | 
			
		||||
1. `.config/example.yml`をコピーし名前を`default.yml`にする。
 | 
			
		||||
 | 
			
		||||
	`cp .config/example.yml .config/default.yml`
 | 
			
		||||
 | 
			
		||||
2. `default.yml` を編集する。
 | 
			
		||||
 | 
			
		||||
*6.* Misskeyのビルド
 | 
			
		||||
@@ -82,43 +105,61 @@ Debianをお使いであれば、`build-essential`パッケージをインスト
 | 
			
		||||
`NODE_ENV=production npm start`するだけです。GLHF!
 | 
			
		||||
 | 
			
		||||
### systemdを用いた起動
 | 
			
		||||
1. systemdサービスのファイルを作成: `/etc/systemd/system/misskey.service`
 | 
			
		||||
1. systemdサービスのファイルを作成
 | 
			
		||||
 | 
			
		||||
	`/etc/systemd/system/misskey.service`
 | 
			
		||||
 | 
			
		||||
2. エディタで開き、以下のコードを貼り付けて保存:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
[Unit]
 | 
			
		||||
Description=Misskey daemon
 | 
			
		||||
	```
 | 
			
		||||
	[Unit]
 | 
			
		||||
	Description=Misskey daemon
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
Type=simple
 | 
			
		||||
User=misskey
 | 
			
		||||
ExecStart=/usr/bin/npm start
 | 
			
		||||
WorkingDirectory=/home/misskey/misskey
 | 
			
		||||
Environment="NODE_ENV=production"
 | 
			
		||||
TimeoutSec=60
 | 
			
		||||
StandardOutput=syslog
 | 
			
		||||
StandardError=syslog
 | 
			
		||||
SyslogIdentifier=misskey
 | 
			
		||||
Restart=always
 | 
			
		||||
	[Service]
 | 
			
		||||
	Type=simple
 | 
			
		||||
	User=misskey
 | 
			
		||||
	ExecStart=/usr/bin/npm start
 | 
			
		||||
	WorkingDirectory=/home/misskey/misskey
 | 
			
		||||
	Environment="NODE_ENV=production"
 | 
			
		||||
	TimeoutSec=60
 | 
			
		||||
	StandardOutput=syslog
 | 
			
		||||
	StandardError=syslog
 | 
			
		||||
	SyslogIdentifier=misskey
 | 
			
		||||
	Restart=always
 | 
			
		||||
 | 
			
		||||
[Install]
 | 
			
		||||
WantedBy=multi-user.target
 | 
			
		||||
```
 | 
			
		||||
CentOSで1024以下のポートを使用してMisskeyを使用する場合は`ExecStart=/usr/bin/sudo /usr/bin/npm start`に変更する必要があります。
 | 
			
		||||
	[Install]
 | 
			
		||||
	WantedBy=multi-user.target
 | 
			
		||||
	```
 | 
			
		||||
 | 
			
		||||
3. `systemctl daemon-reload ; systemctl enable misskey` systemdを再読み込みしmisskeyサービスを有効化
 | 
			
		||||
4. `systemctl start misskey` misskeyサービスの起動
 | 
			
		||||
	CentOSで1024以下のポートを使用してMisskeyを使用する場合は`ExecStart=/usr/bin/sudo /usr/bin/npm start`に変更する必要があります。
 | 
			
		||||
 | 
			
		||||
3. systemdを再読み込みしmisskeyサービスを有効化
 | 
			
		||||
 | 
			
		||||
	`systemctl daemon-reload ; systemctl enable misskey`
 | 
			
		||||
 | 
			
		||||
4. misskeyサービスの起動
 | 
			
		||||
 | 
			
		||||
	`systemctl start misskey`
 | 
			
		||||
 | 
			
		||||
`systemctl status misskey`と入力すると、サービスの状態を調べることができます。
 | 
			
		||||
 | 
			
		||||
### Misskeyを最新バージョンにアップデートする方法:
 | 
			
		||||
1. `git fetch`
 | 
			
		||||
2. `git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)`
 | 
			
		||||
2.  
 | 
			
		||||
 | 
			
		||||
	```bash
 | 
			
		||||
	git tag | grep '^10\.' | sort -V --reverse | \
 | 
			
		||||
	while read tag_name; do \
 | 
			
		||||
	if ! curl -s "https://api.github.com/repos/syuilo/misskey/releases/tags/$tag_name" \
 | 
			
		||||
	| grep -qE '"(draft|prerelease)": true'; \
 | 
			
		||||
	then git checkout $tag_name; break; fi ; done
 | 
			
		||||
	```
 | 
			
		||||
 | 
			
		||||
3. `npm install`
 | 
			
		||||
4. `NODE_ENV=production npm run build`
 | 
			
		||||
5. [ChangeLog](../CHANGELOG.md)でマイグレーション情報を確認する
 | 
			
		||||
 | 
			
		||||
なにか問題が発生した場合は、`npm run clean`すると直る場合があります。
 | 
			
		||||
なにか問題が発生した場合は、`npm run clean`または`npm run cleanall`すると直る場合があります。
 | 
			
		||||
 | 
			
		||||
----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,6 @@
 | 
			
		||||
import * as gulp from 'gulp';
 | 
			
		||||
import * as gutil from 'gulp-util';
 | 
			
		||||
import * as ts from 'gulp-typescript';
 | 
			
		||||
const yaml = require('gulp-yaml');
 | 
			
		||||
const sourcemaps = require('gulp-sourcemaps');
 | 
			
		||||
import tslint from 'gulp-tslint';
 | 
			
		||||
const cssnano = require('gulp-cssnano');
 | 
			
		||||
@@ -126,12 +125,6 @@ gulp.task('copy:client', () =>
 | 
			
		||||
			.pipe(gulp.dest('./built/client/assets/'))
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
gulp.task('locales', () =>
 | 
			
		||||
	gulp.src('./locales/*.yml')
 | 
			
		||||
		.pipe(yaml({ schema: 'DEFAULT_SAFE_SCHEMA' }))
 | 
			
		||||
		.pipe(gulp.dest('./built/client/assets/locales/'))
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
gulp.task('doc', () =>
 | 
			
		||||
	gulp.src('./src/docs/**/*.styl')
 | 
			
		||||
		.pipe(stylus())
 | 
			
		||||
@@ -149,7 +142,6 @@ gulp.task('build', gulp.parallel(
 | 
			
		||||
	'build:ts',
 | 
			
		||||
	'build:copy',
 | 
			
		||||
	'build:client',
 | 
			
		||||
	'locales',
 | 
			
		||||
	'doc'
 | 
			
		||||
));
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1624
									
								
								locales/ca-ES.yml
									
									
									
									
									
								
							
							
						
						
									
										1624
									
								
								locales/ca-ES.yml
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1193
									
								
								locales/cs-CZ.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1193
									
								
								locales/cs-CZ.yml
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1180
									
								
								locales/de-DE.yml
									
									
									
									
									
								
							
							
						
						
									
										1180
									
								
								locales/de-DE.yml
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,7 +1,6 @@
 | 
			
		||||
---
 | 
			
		||||
meta:
 | 
			
		||||
  lang: "English"
 | 
			
		||||
  divider: ""
 | 
			
		||||
common:
 | 
			
		||||
  misskey: "A ⭐ of the fediverse"
 | 
			
		||||
  about-title: "A ⭐ of the fediverse."
 | 
			
		||||
@@ -25,8 +24,8 @@ common:
 | 
			
		||||
  application-authorization: "Application authorizations"
 | 
			
		||||
  close: "Close"
 | 
			
		||||
  do-not-copy-paste: "Please do not enter or paste the code here. Account may be compromised."
 | 
			
		||||
  load-more: "Load more"
 | 
			
		||||
  enter-password: "Please enter the Password"
 | 
			
		||||
  load-more: "Read more"
 | 
			
		||||
  enter-password: "Enter your password"
 | 
			
		||||
  2fa: "Two-factor authentication"
 | 
			
		||||
  customize-home: "Customize home layout"
 | 
			
		||||
  featured-notes: "Featured notes"
 | 
			
		||||
@@ -115,7 +114,7 @@ common:
 | 
			
		||||
    a: "What are you doing?"
 | 
			
		||||
    b: "What's happening?"
 | 
			
		||||
    c: "What’s on your mind?"
 | 
			
		||||
    d: "Would you post any words?"
 | 
			
		||||
    d: "What do you want to say?"
 | 
			
		||||
    e: "Write here"
 | 
			
		||||
    f: "Waiting for your writing."
 | 
			
		||||
  settings: "Settings"
 | 
			
		||||
@@ -170,9 +169,9 @@ common:
 | 
			
		||||
    deck-column-align-flexible: "Flexible"
 | 
			
		||||
    deck-column-width: "Deck column width"
 | 
			
		||||
    deck-column-width-narrow: "Narrow"
 | 
			
		||||
    deck-column-width-narrower: "Somewhat narrow"
 | 
			
		||||
    deck-column-width-narrower: "Narrower"
 | 
			
		||||
    deck-column-width-normal: "Regular"
 | 
			
		||||
    deck-column-width-wider: "Somewhat wide"
 | 
			
		||||
    deck-column-width-wider: "Slightly wide"
 | 
			
		||||
    deck-column-width-wide: "Wide"
 | 
			
		||||
    use-shadow: "Use shadows in the UI"
 | 
			
		||||
    rounded-corners: "Round the corners of the UI"
 | 
			
		||||
@@ -224,8 +223,8 @@ common:
 | 
			
		||||
  search: "Search"
 | 
			
		||||
  delete: "Delete"
 | 
			
		||||
  loading: "Loading"
 | 
			
		||||
  ok: "It's OK"
 | 
			
		||||
  cancel: "Quit"
 | 
			
		||||
  ok: "Confirm"
 | 
			
		||||
  cancel: "Cancel"
 | 
			
		||||
  update-available-title: "Update available"
 | 
			
		||||
  update-available: "A new version of Misskey is now available({newer}, the current version is {current}). Reload the page to apply updates."
 | 
			
		||||
  my-token-regenerated: "Your token has been regenerated, so you will be signed out."
 | 
			
		||||
@@ -286,7 +285,7 @@ auth/views/form.vue:
 | 
			
		||||
  account-read: "View account information."
 | 
			
		||||
  account-write: "Modify account information."
 | 
			
		||||
  note-write: "Post."
 | 
			
		||||
  like-write: "React to posts."
 | 
			
		||||
  like-write: "Express yourself about this post."
 | 
			
		||||
  following-write: "Follow and unfollow."
 | 
			
		||||
  drive-read: "Read your drive."
 | 
			
		||||
  drive-write: "Upload/delete files in your drive."
 | 
			
		||||
@@ -305,7 +304,7 @@ auth/views/index.vue:
 | 
			
		||||
  error: "Session does not exist."
 | 
			
		||||
  sign-in: "Please sign in."
 | 
			
		||||
common/views/pages/explore.vue:
 | 
			
		||||
  verified-users: "Verified accounts"
 | 
			
		||||
  verified-users: "Official accounts"
 | 
			
		||||
  popular-users: "Popular users"
 | 
			
		||||
  recently-updated-users: "Recently active users"
 | 
			
		||||
  recently-registered-users: "Users who joined recently"
 | 
			
		||||
@@ -315,6 +314,7 @@ common/views/pages/explore.vue:
 | 
			
		||||
  users-info: "Currently, {users} users are registered here"
 | 
			
		||||
common/views/components/url-preview.vue:
 | 
			
		||||
  enable-player: "Enable playback"
 | 
			
		||||
  disable-player: "Close the player"
 | 
			
		||||
common/views/components/user-list.vue:
 | 
			
		||||
  no-users: "There are no users."
 | 
			
		||||
common/views/components/games/reversi/reversi.vue:
 | 
			
		||||
@@ -483,23 +483,42 @@ common/views/components/user-menu.vue:
 | 
			
		||||
  report-abuse: "Report abuse"
 | 
			
		||||
  report-abuse-detail: "What kind of nuisance did you encounter?"
 | 
			
		||||
  report-abuse-reported: "The issue has been reported to the administrator. Your cooperation is much appreciated."
 | 
			
		||||
  silence: "Mute"
 | 
			
		||||
  unsilence: "Unmute"
 | 
			
		||||
  silence: "Silence"
 | 
			
		||||
  unsilence: "Unsilence"
 | 
			
		||||
  suspend: "Suspend"
 | 
			
		||||
  unsuspend: "Unsuspend"
 | 
			
		||||
common/views/components/poll.vue:
 | 
			
		||||
  vote-to: "Vote for '{}'"
 | 
			
		||||
  vote-count: "{} votes"
 | 
			
		||||
  total-users: "{} users voted"
 | 
			
		||||
  total-votes: "{} votes in total"
 | 
			
		||||
  vote: "Vote"
 | 
			
		||||
  show-result: "Show results"
 | 
			
		||||
  voted: "Voted"
 | 
			
		||||
  closed: "Ended"
 | 
			
		||||
  remaining-days: "{d} days, {h} hours remain"
 | 
			
		||||
  remaining-hours: "{h} hours, and {m} minutes remain"
 | 
			
		||||
  remaining-minutes: "{m} minutes, and {s} seconds remaining"
 | 
			
		||||
  remaining-seconds: "{s} seconds remaining"
 | 
			
		||||
common/views/components/poll-editor.vue:
 | 
			
		||||
  no-only-one-choice: "At least two choices are required"
 | 
			
		||||
  choice-n: "Choice {}"
 | 
			
		||||
  remove: "Delete the choice"
 | 
			
		||||
  add: "+ Add a choice"
 | 
			
		||||
  destroy: "Discard the poll"
 | 
			
		||||
  multiple: "More than one answer is allowed"
 | 
			
		||||
  expiration: "Valid until"
 | 
			
		||||
  infinite: "Indefinitely"
 | 
			
		||||
  at: "Date and time pick"
 | 
			
		||||
  after: "Progression specifics"
 | 
			
		||||
  no-more: "You cannot add any more"
 | 
			
		||||
  deadline-date: "Finish date"
 | 
			
		||||
  deadline-time: "Time duration"
 | 
			
		||||
  interval: "Duration"
 | 
			
		||||
  unit: "Unit"
 | 
			
		||||
  second: "Seconds"
 | 
			
		||||
  minute: "Minutes"
 | 
			
		||||
  hour: "Hours"
 | 
			
		||||
  day: "S"
 | 
			
		||||
common/views/components/reaction-picker.vue:
 | 
			
		||||
  choose-reaction: "Send a reaction"
 | 
			
		||||
common/views/components/emoji-picker.vue:
 | 
			
		||||
@@ -521,7 +540,7 @@ common/views/components/signin.vue:
 | 
			
		||||
  signin-with-twitter: "Log in with Twitter"
 | 
			
		||||
  signin-with-github: "Sign in with GitHub"
 | 
			
		||||
  signin-with-discord: "Sign in with Discord"
 | 
			
		||||
  login-failed: "Log in failed. Make sure you have entered your correct username and password."
 | 
			
		||||
  login-failed: "Logging in has failed. Make sure you have entered the correct username and password."
 | 
			
		||||
common/views/components/signup.vue:
 | 
			
		||||
  invitation-code: "Invitation code"
 | 
			
		||||
  invitation-info: "If you do not have an invitation code, please contact an <a href=\"{}\">administrator</a>."
 | 
			
		||||
@@ -629,12 +648,16 @@ common/views/components/profile-editor.vue:
 | 
			
		||||
  email-verified: "Your email has been verified."
 | 
			
		||||
  email-not-verified: "Email address is not confirmed. Please check your inbox."
 | 
			
		||||
  export: "Export"
 | 
			
		||||
  import: "Import"
 | 
			
		||||
  export-and-import: "Export and Import"
 | 
			
		||||
  export-targets:
 | 
			
		||||
    all-notes: "All posted Notes"
 | 
			
		||||
    following-list: "List of followers"
 | 
			
		||||
    mute-list: "List of muted accounts"
 | 
			
		||||
    blocking-list: "List of blocked accounts"
 | 
			
		||||
    user-lists: "Lists"
 | 
			
		||||
  export-requested: "You have requested an export. This may take a while. After the export is complete, the resulting file will be added to the drive."
 | 
			
		||||
  import-requested: "You have initiated an import. This may take quite some time."
 | 
			
		||||
  enter-password: "Please enter your password"
 | 
			
		||||
  danger-zone: "Cautious options"
 | 
			
		||||
  delete-account: "Remove the account"
 | 
			
		||||
@@ -816,10 +839,6 @@ desktop/views/components/home.vue:
 | 
			
		||||
desktop/views/input-dialog.vue:
 | 
			
		||||
  cancel: "Cancel"
 | 
			
		||||
  ok: "OK"
 | 
			
		||||
desktop/views/components/messaging-room-window.vue:
 | 
			
		||||
  title: "Messages:"
 | 
			
		||||
desktop/views/components/messaging-window.vue:
 | 
			
		||||
  title: "Messaging"
 | 
			
		||||
desktop/views/components/note-detail.vue:
 | 
			
		||||
  private: "Post is private"
 | 
			
		||||
  deleted: "Post has been removed"
 | 
			
		||||
@@ -858,7 +877,6 @@ desktop/views/components/post-form.vue:
 | 
			
		||||
  posting: "Posting"
 | 
			
		||||
  attach-media-from-local: "Attach media from your device"
 | 
			
		||||
  attach-media-from-drive: "Attach media from your Drive"
 | 
			
		||||
  attach-cancel: "Cancel attachment"
 | 
			
		||||
  insert-a-kao: "v('ω')v"
 | 
			
		||||
  create-poll: "Create a poll"
 | 
			
		||||
  text-remain: "{} characters remaining"
 | 
			
		||||
@@ -951,6 +969,10 @@ common/views/components/password-settings.vue:
 | 
			
		||||
  not-match: "The new passwords do not match"
 | 
			
		||||
  changed: "Password changed"
 | 
			
		||||
  failed: "Failed to change password"
 | 
			
		||||
common/views/components/post-form-attaches.vue:
 | 
			
		||||
  attach-cancel: "Remove Attachment"
 | 
			
		||||
  mark-as-sensitive: "Mark as 'sensitive'"
 | 
			
		||||
  unmark-as-sensitive: "Unmark as 'sensitive'"
 | 
			
		||||
desktop/views/components/sub-note-content.vue:
 | 
			
		||||
  private: "This post is private"
 | 
			
		||||
  deleted: "This post has been deleted"
 | 
			
		||||
@@ -969,7 +991,7 @@ desktop/views/components/timeline.vue:
 | 
			
		||||
  hybrid: "Social"
 | 
			
		||||
  global: "Global"
 | 
			
		||||
  mentions: "Mentions"
 | 
			
		||||
  messages: "Messages"
 | 
			
		||||
  messages: "Direct posts"
 | 
			
		||||
  list: "Lists"
 | 
			
		||||
  hashtag: "Hashtag"
 | 
			
		||||
  add-tag-timeline: "Add hashtag cloud"
 | 
			
		||||
@@ -1034,7 +1056,7 @@ admin/views/dashboard.vue:
 | 
			
		||||
  this-instance: "This instance"
 | 
			
		||||
  federated: "Federated"
 | 
			
		||||
admin/views/queue.vue:
 | 
			
		||||
  operation: "Action(s)"
 | 
			
		||||
  title: "Queue"
 | 
			
		||||
  remove-all-jobs: "Clear all queued jobs"
 | 
			
		||||
admin/views/abuse.vue:
 | 
			
		||||
  title: "Abuse"
 | 
			
		||||
@@ -1090,6 +1112,8 @@ admin/views/instance.vue:
 | 
			
		||||
  disable-local-timeline: "Disable the Local Timeline"
 | 
			
		||||
  disable-global-timeline: "Disable global timeline"
 | 
			
		||||
  disabling-timelines-info: "Even if you disable these timelines, the administrator as well as moderators can use them continually."
 | 
			
		||||
  enable-emoji-reaction: "Enable pictograms for reactions"
 | 
			
		||||
  use-star-for-reaction-fallback: "Use the star as fallback for unknown reaction"
 | 
			
		||||
  invite: "Invite"
 | 
			
		||||
  save: "Save"
 | 
			
		||||
  saved: "Saved"
 | 
			
		||||
@@ -1178,8 +1202,8 @@ admin/views/users.vue:
 | 
			
		||||
  unsuspend: "Unsuspend"
 | 
			
		||||
  unsuspend-confirm: "Are you sure you want to unsuspend this account?"
 | 
			
		||||
  unsuspended: "The user has successfully unsuspended."
 | 
			
		||||
  make-silence: "Mute"
 | 
			
		||||
  unmake-silence: "Unmute"
 | 
			
		||||
  make-silence: "Silence"
 | 
			
		||||
  unmake-silence: "Unsilence"
 | 
			
		||||
  verify: "Verify account"
 | 
			
		||||
  verify-confirm: "Do you want this to be a verified account?"
 | 
			
		||||
  verified: "The account is now being verified"
 | 
			
		||||
@@ -1197,7 +1221,7 @@ admin/views/users.vue:
 | 
			
		||||
      updatedAtAsc: "Last Updated (Ascending)"
 | 
			
		||||
      updatedAtDesc: "Last Updated (Descending)"
 | 
			
		||||
    state:
 | 
			
		||||
      title: "Status"
 | 
			
		||||
      title: "Sort"
 | 
			
		||||
      all: "All"
 | 
			
		||||
      admin: "Administrator"
 | 
			
		||||
      moderator: "Moderator"
 | 
			
		||||
@@ -1252,13 +1276,14 @@ admin/views/announcements.vue:
 | 
			
		||||
admin/views/hashtags.vue:
 | 
			
		||||
  hided-tags: "Hidden Tags"
 | 
			
		||||
admin/views/federation.vue:
 | 
			
		||||
  federation: "Federation"
 | 
			
		||||
  instance: "Instance"
 | 
			
		||||
  host: "Host"
 | 
			
		||||
  notes: "Notes"
 | 
			
		||||
  users: "Users"
 | 
			
		||||
  following: "Following"
 | 
			
		||||
  followers: "Followers"
 | 
			
		||||
  status: "Status"
 | 
			
		||||
  caught-at: "Created at"
 | 
			
		||||
  status: "Statuses"
 | 
			
		||||
  latest-request-sent-at: "Time of last request sent"
 | 
			
		||||
  latest-request-received-at: "Last request received at"
 | 
			
		||||
  remove-all-following: "Withold all followers"
 | 
			
		||||
@@ -1266,7 +1291,7 @@ admin/views/federation.vue:
 | 
			
		||||
  block: "Block"
 | 
			
		||||
  marked-as-closed: "Marked as closed"
 | 
			
		||||
  lookup: "Look up"
 | 
			
		||||
  instances: "Instances"
 | 
			
		||||
  instances: "Federated"
 | 
			
		||||
  instance-not-registered: "The instance has not been discovered"
 | 
			
		||||
  sort: "Sort by"
 | 
			
		||||
  sorts:
 | 
			
		||||
@@ -1274,19 +1299,19 @@ admin/views/federation.vue:
 | 
			
		||||
    caughtAtDesc: "Date of discovery (Descending)"
 | 
			
		||||
    lastCommunicatedAtAsc: "The date and time of the older interactions"
 | 
			
		||||
    lastCommunicatedAtDesc: "The date and time of the newer interactions"
 | 
			
		||||
    notesAsc: "Order by least Notes posted"
 | 
			
		||||
    notesDesc: "Order by most Notes posted"
 | 
			
		||||
    notesAsc: "Least Notes posted"
 | 
			
		||||
    notesDesc: "Most Notes posted"
 | 
			
		||||
    usersAsc: "Less followers"
 | 
			
		||||
    usersDesc: "More followers"
 | 
			
		||||
    followingAsc: "Least followed"
 | 
			
		||||
    followingDesc: "Has more followers"
 | 
			
		||||
    followersAsc: "Sort by having less followers"
 | 
			
		||||
    followersDesc: "Sort by the larger number of followers"
 | 
			
		||||
    followingDesc: "Most followed"
 | 
			
		||||
    followersAsc: "Having less followers"
 | 
			
		||||
    followersDesc: "The largest number of followers"
 | 
			
		||||
    driveUsageAsc: "Least storage used"
 | 
			
		||||
    driveUsageDesc: "Most storage used"
 | 
			
		||||
    driveFilesAsc: "By the smallest number of files stored on Drive"
 | 
			
		||||
    driveFilesDesc: "By the largest number of files stored on Drive"
 | 
			
		||||
  state: "Status"
 | 
			
		||||
    driveFilesAsc: "Least files stored on Drive"
 | 
			
		||||
    driveFilesDesc: "The largest number of files stored on Drive"
 | 
			
		||||
  state: "Sort"
 | 
			
		||||
  states:
 | 
			
		||||
    all: "All"
 | 
			
		||||
    blocked: "Blocked"
 | 
			
		||||
@@ -1329,8 +1354,6 @@ desktop/views/pages/selectdrive.vue:
 | 
			
		||||
desktop/views/pages/search.vue:
 | 
			
		||||
  not-available: "Search feature is turned off in the settings for this instance."
 | 
			
		||||
  not-found: "No posts were found for '{q}'"
 | 
			
		||||
desktop/views/pages/share.vue:
 | 
			
		||||
  share-with: "Share on {name}"
 | 
			
		||||
desktop/views/pages/tag.vue:
 | 
			
		||||
  no-posts-found: "No posts contains \"{q}\" found."
 | 
			
		||||
desktop/views/pages/user-list.users.vue:
 | 
			
		||||
@@ -1354,7 +1377,7 @@ desktop/views/pages/user/user.header.vue:
 | 
			
		||||
  following: "Following"
 | 
			
		||||
  followers: "Followers"
 | 
			
		||||
  is-bot: "This account is a Bot"
 | 
			
		||||
  no-description: "The user has not written their profile introduction"
 | 
			
		||||
  no-description: "This user has not written their profile introduction"
 | 
			
		||||
  years-old: "{age} years old"
 | 
			
		||||
  year: "/"
 | 
			
		||||
  month: "/"
 | 
			
		||||
@@ -1365,8 +1388,6 @@ desktop/views/pages/user/user.timeline.vue:
 | 
			
		||||
  with-replies: "Posts and replies"
 | 
			
		||||
  with-media: "Media"
 | 
			
		||||
  my-posts: "My posts"
 | 
			
		||||
desktop/views/widgets/messaging.vue:
 | 
			
		||||
  title: "Message"
 | 
			
		||||
desktop/views/widgets/notifications.vue:
 | 
			
		||||
  title: "Notifications"
 | 
			
		||||
desktop/views/widgets/polls.vue:
 | 
			
		||||
@@ -1488,7 +1509,7 @@ mobile/views/pages/home.vue:
 | 
			
		||||
  hybrid: "Social"
 | 
			
		||||
  global: "Global"
 | 
			
		||||
  mentions: "Mentions"
 | 
			
		||||
  messages: "Messages"
 | 
			
		||||
  messages: "Direct posts"
 | 
			
		||||
mobile/views/pages/tag.vue:
 | 
			
		||||
  no-posts-found: "No posts contains \"{q}\" found."
 | 
			
		||||
mobile/views/pages/widgets.vue:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1041
									
								
								locales/es-ES.yml
									
									
									
									
									
								
							
							
						
						
									
										1041
									
								
								locales/es-ES.yml
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,7 +1,6 @@
 | 
			
		||||
---
 | 
			
		||||
meta:
 | 
			
		||||
  lang: "Français"
 | 
			
		||||
  divider: ""
 | 
			
		||||
common:
 | 
			
		||||
  misskey: "Une ⭐ du fédiverse"
 | 
			
		||||
  about-title: "Une ⭐ du fédiverse."
 | 
			
		||||
@@ -30,15 +29,13 @@ common:
 | 
			
		||||
  2fa: "Authentification à deux facteurs"
 | 
			
		||||
  customize-home: "Personnaliser la disposition de votre accueil"
 | 
			
		||||
  featured-notes: "Les notes mises en avant"
 | 
			
		||||
  dark-mode: "ダークモード"
 | 
			
		||||
  signin: "ログイン"
 | 
			
		||||
  signup: "新規登録"
 | 
			
		||||
  signout: "ログアウト"
 | 
			
		||||
  reload-to-apply-the-setting: "この設定を反映するにはページをリロードする必要があります。今すぐリロードしますか?"
 | 
			
		||||
  dark-mode: "Mode nuit"
 | 
			
		||||
  signin: "Se connecter"
 | 
			
		||||
  signup: "S'enregistrer"
 | 
			
		||||
  signout: "Se déconnecter"
 | 
			
		||||
  got-it: "J’ai compris !"
 | 
			
		||||
  customization-tips:
 | 
			
		||||
    title: "Conseils de personnalisation"
 | 
			
		||||
    paragraph: "<p>ホームのカスタマイズでは、ウィジェットを追加/削除したり、ドラッグ&ドロップして並べ替えたりすることができます。</p><p>一部のウィジェットは、<strong><strong>右</strong>クリック</strong>することで表示を変更することができます。</p><p>ウィジェットを削除するには、ヘッダーの<strong>「ゴミ箱」</strong>と書かれたエリアにウィジェットをドラッグ&ドロップします。</p><p>カスタマイズを終了するには、右上の「完了」をクリックします。</p>"
 | 
			
		||||
    gotit: "Compris !"
 | 
			
		||||
  notification:
 | 
			
		||||
    file-uploaded: "Le fichier a été téléversé !"
 | 
			
		||||
@@ -69,7 +66,7 @@ common:
 | 
			
		||||
  explore: "Découvrir"
 | 
			
		||||
  following: "Suit"
 | 
			
		||||
  followers: "Abonné·e·s"
 | 
			
		||||
  favorites: "お気に入り"
 | 
			
		||||
  favorites: "Mettre cette note en favoris"
 | 
			
		||||
  empty-timeline-info:
 | 
			
		||||
    follow-users-to-make-your-timeline: "Les utilisateurs suivants afficheront leurs publications sur votre fil."
 | 
			
		||||
    explore: "Trouver des utilisateurs"
 | 
			
		||||
@@ -118,114 +115,54 @@ common:
 | 
			
		||||
    d: "Désirez-vous publier quelques mots ?"
 | 
			
		||||
    e: "Écrivez ici"
 | 
			
		||||
    f: "En attente de vos écrits"
 | 
			
		||||
  settings: "設定"
 | 
			
		||||
  settings: "Paramètres"
 | 
			
		||||
  _settings:
 | 
			
		||||
    profile: "プロフィール"
 | 
			
		||||
    notification: "通知"
 | 
			
		||||
    apps: "アプリ"
 | 
			
		||||
    tags: "ハッシュタグ"
 | 
			
		||||
    mute-and-block: "ミュート/ブロック"
 | 
			
		||||
    blocking: "ブロック"
 | 
			
		||||
    security: "セキュリティ"
 | 
			
		||||
    signin: "ログイン履歴"
 | 
			
		||||
    password: "パスワード"
 | 
			
		||||
    other: "その他"
 | 
			
		||||
    appearance: "デザイン"
 | 
			
		||||
    behavior: "動作"
 | 
			
		||||
    fetch-on-scroll: "スクロールで自動読み込み"
 | 
			
		||||
    fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。"
 | 
			
		||||
    note-visibility: "投稿の公開範囲"
 | 
			
		||||
    default-note-visibility: "デフォルトの公開範囲"
 | 
			
		||||
    remember-note-visibility: "投稿の公開範囲を記憶する"
 | 
			
		||||
    web-search-engine: "ウェブ検索エンジン"
 | 
			
		||||
    web-search-engine-desc: "例: https://www.google.com/?#q={{query}}"
 | 
			
		||||
    keep-cw: "CW保持"
 | 
			
		||||
    keep-cw-desc: "投稿にリプライする際、リプライ元の投稿にCWが設定されていたとき、デフォルトで同じCWを設定するようにします。"
 | 
			
		||||
    i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
 | 
			
		||||
    show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示"
 | 
			
		||||
    use-avatar-reversi-stones: "リバーシの石にアバターを使う"
 | 
			
		||||
    disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
 | 
			
		||||
    disable-showing-animated-images: "アニメーション画像を再生しない"
 | 
			
		||||
    suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
 | 
			
		||||
    always-show-nsfw: "常に閲覧注意のメディアを表示する"
 | 
			
		||||
    always-mark-nsfw: "常にメディアを閲覧注意として投稿"
 | 
			
		||||
    show-full-acct: "ユーザー名のホストを省略しない"
 | 
			
		||||
    show-via: "viaを表示する"
 | 
			
		||||
    reduce-motion: "UIの動きを減らす"
 | 
			
		||||
    this-setting-is-this-device-only: "このデバイスのみ"
 | 
			
		||||
    use-os-default-emojis: "OS標準の絵文字を使用"
 | 
			
		||||
    line-width: "線の太さ"
 | 
			
		||||
    line-width-thin: "細い"
 | 
			
		||||
    line-width-normal: "普通"
 | 
			
		||||
    line-width-thick: "太い"
 | 
			
		||||
    font-size: "文字の大きさ"
 | 
			
		||||
    font-size-x-small: "小さい"
 | 
			
		||||
    font-size-small: "少し小さい"
 | 
			
		||||
    font-size-medium: "普通"
 | 
			
		||||
    font-size-large: "少し大きい"
 | 
			
		||||
    font-size-x-large: "大きい"
 | 
			
		||||
    deck-column-align: "デッキのカラムの配置"
 | 
			
		||||
    deck-column-align-center: "中央"
 | 
			
		||||
    deck-column-align-left: "左"
 | 
			
		||||
    deck-column-align-flexible: "フレキシブル"
 | 
			
		||||
    deck-column-width: "デッキのカラムの幅"
 | 
			
		||||
    deck-column-width-narrow: "狭"
 | 
			
		||||
    deck-column-width-narrower: "やや狭"
 | 
			
		||||
    deck-column-width-normal: "普通"
 | 
			
		||||
    deck-column-width-wider: "やや広"
 | 
			
		||||
    deck-column-width-wide: "広"
 | 
			
		||||
    use-shadow: "UIに影を使用"
 | 
			
		||||
    rounded-corners: "UIの角を丸める"
 | 
			
		||||
    circle-icons: "円形のアイコンを使用"
 | 
			
		||||
    contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
    wallpaper: "壁紙"
 | 
			
		||||
    choose-wallpaper: "壁紙を選択"
 | 
			
		||||
    delete-wallpaper: "壁紙を削除"
 | 
			
		||||
    post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
 | 
			
		||||
    show-clock-on-header: "右上に時計を表示する"
 | 
			
		||||
    show-reply-target: "リプライ先を表示する"
 | 
			
		||||
    timeline: "タイムライン"
 | 
			
		||||
    show-my-renotes: "自分の行ったRenoteをタイムラインに表示する"
 | 
			
		||||
    show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
 | 
			
		||||
    show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
 | 
			
		||||
    remain-deleted-note: "削除された投稿を表示し続ける"
 | 
			
		||||
    sound: "サウンド"
 | 
			
		||||
    enable-sounds: "サウンドを有効にする"
 | 
			
		||||
    enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
 | 
			
		||||
    volume: "ボリューム"
 | 
			
		||||
    test: "テスト"
 | 
			
		||||
    update: "Misskey Update"
 | 
			
		||||
    version: "バージョン:"
 | 
			
		||||
    latest-version: "最新のバージョン:"
 | 
			
		||||
    update-checking: "アップデートを確認中"
 | 
			
		||||
    do-update: "アップデートを確認"
 | 
			
		||||
    update-settings: "詳細設定"
 | 
			
		||||
    no-updates: "利用可能な更新はありません"
 | 
			
		||||
    no-updates-desc: "お使いのMisskeyは最新です。"
 | 
			
		||||
    update-available: "新しいバージョンが利用可能です"
 | 
			
		||||
    update-available-desc: "ページを再度読み込みすると更新が適用されます。"
 | 
			
		||||
    advanced-settings: "高度な設定"
 | 
			
		||||
    debug-mode: "デバッグモードを有効にする"
 | 
			
		||||
    debug-mode-desc: "この設定はブラウザに記憶されます。"
 | 
			
		||||
    navbar-position: "ナビゲーションバーの位置"
 | 
			
		||||
    navbar-position-top: "上"
 | 
			
		||||
    navbar-position-left: "左"
 | 
			
		||||
    navbar-position-right: "右"
 | 
			
		||||
    i-am-under-limited-internet: "私は通信を制限されている"
 | 
			
		||||
    post-style: "投稿の表示スタイル"
 | 
			
		||||
    post-style-standard: "標準"
 | 
			
		||||
    post-style-smart: "スマート"
 | 
			
		||||
    notification-position: "通知の表示"
 | 
			
		||||
    notification-position-bottom: "下"
 | 
			
		||||
    notification-position-top: "上"
 | 
			
		||||
    disable-via-mobile: "「モバイルからの投稿」フラグを付けない"
 | 
			
		||||
    load-raw-images: "添付された画像を高画質で表示する"
 | 
			
		||||
    load-remote-media: "リモートサーバーのメディアを表示する"
 | 
			
		||||
    profile: "Votre profil"
 | 
			
		||||
    notification: "Notifications"
 | 
			
		||||
    apps: "Applications"
 | 
			
		||||
    tags: "Hashtags"
 | 
			
		||||
    blocking: "En cours blocage"
 | 
			
		||||
    security: "Sécurité"
 | 
			
		||||
    signin: "Historique des connexions"
 | 
			
		||||
    password: "Mot de passe"
 | 
			
		||||
    other: "Avancé"
 | 
			
		||||
    appearance: "Apparence"
 | 
			
		||||
    behavior: "Comportement"
 | 
			
		||||
    fetch-on-scroll: "Chargement automatique lors du défilement"
 | 
			
		||||
    note-visibility: "Visibilité de la publication"
 | 
			
		||||
    default-note-visibility: "Visibilité par défaut"
 | 
			
		||||
    remember-note-visibility: "Se souvenir du mode de visibilité de la publication"
 | 
			
		||||
    web-search-engine: "Moteur de recherche Web"
 | 
			
		||||
    web-search-engine-desc: "Exemple : https://www.google.com/?#q={{query}}"
 | 
			
		||||
    show-via: "Afficher via"
 | 
			
		||||
    reduce-motion: "Réduire les animations dans l’interface utilisateur"
 | 
			
		||||
    this-setting-is-this-device-only: "Uniquement sur cet appareil"
 | 
			
		||||
    use-os-default-emojis: "Utiliser les émojis standards du système"
 | 
			
		||||
    line-width: "Epaisseur du trait"
 | 
			
		||||
    line-width-thin: "Fine"
 | 
			
		||||
    line-width-normal: "Normale"
 | 
			
		||||
    line-width-thick: "Épaisse"
 | 
			
		||||
    font-size: "Taille du texte"
 | 
			
		||||
    font-size-medium: "Normale"
 | 
			
		||||
    font-size-x-large: "Large"
 | 
			
		||||
    deck-column-align-center: "Centrer"
 | 
			
		||||
    deck-column-align-left: "À gauche"
 | 
			
		||||
    deck-column-align-flexible: "Flexible"
 | 
			
		||||
    deck-column-width: "Largeur des colonnes du Deck"
 | 
			
		||||
    deck-column-width-normal: "Normale"
 | 
			
		||||
    timeline: "Fil d’actualité"
 | 
			
		||||
    navbar-position-top: "en haut"
 | 
			
		||||
    navbar-position-left: "À gauche"
 | 
			
		||||
    navbar-position-right: "à droite"
 | 
			
		||||
    post-style-standard: "Standard"
 | 
			
		||||
    post-style-smart: "Intelligent"
 | 
			
		||||
    notification-position: "Afficher les notifications"
 | 
			
		||||
    notification-position-bottom: "en bas"
 | 
			
		||||
    notification-position-top: "en haut"
 | 
			
		||||
  search: "Recherche"
 | 
			
		||||
  delete: "Supprimer"
 | 
			
		||||
  loading: "Chargement en cours …"
 | 
			
		||||
  ok: "おk"
 | 
			
		||||
  cancel: "やめる"
 | 
			
		||||
  cancel: "Quitter"
 | 
			
		||||
  update-available-title: "Mise à jour disponible"
 | 
			
		||||
  update-available: "Une nouvelle version de Misskey est disponible ({newer}, version actuelle: {current}). Veuillez recharger la page pour appliquer la mise à jour."
 | 
			
		||||
  my-token-regenerated: "Votre jeton vient d’être généré, vous allez maintenant être déconnecté."
 | 
			
		||||
@@ -313,8 +250,6 @@ common/views/pages/explore.vue:
 | 
			
		||||
  federated: "Du Fédiverse"
 | 
			
		||||
  explore: "Explorer {host}"
 | 
			
		||||
  users-info: "Actuellement, {users} utilisateurs se sont inscrit ici"
 | 
			
		||||
common/views/components/url-preview.vue:
 | 
			
		||||
  enable-player: "プレイヤーを開く"
 | 
			
		||||
common/views/components/user-list.vue:
 | 
			
		||||
  no-users: "Il n'y a aucun utilisateur"
 | 
			
		||||
common/views/components/games/reversi/reversi.vue:
 | 
			
		||||
@@ -349,7 +284,6 @@ common/views/components/games/reversi/reversi.room.vue:
 | 
			
		||||
  black-or-white: "Noirs/Blancs"
 | 
			
		||||
  black-is: "{} Noirs"
 | 
			
		||||
  rules: "Règles"
 | 
			
		||||
  is-llotheo: "石の少ない方が勝ち(ロセオ)"
 | 
			
		||||
  looped-map: "Carte en boucle"
 | 
			
		||||
  can-put-everywhere: "Peut poser partout"
 | 
			
		||||
  settings-of-the-bot: "Configuration du bot"
 | 
			
		||||
@@ -490,7 +424,6 @@ common/views/components/user-menu.vue:
 | 
			
		||||
common/views/components/poll.vue:
 | 
			
		||||
  vote-to: "Voter pour '{}'"
 | 
			
		||||
  vote-count: "{} votes"
 | 
			
		||||
  total-users: "{} utilisateur·rice·s ont voté"
 | 
			
		||||
  vote: "Vote"
 | 
			
		||||
  show-result: "Montrer les résultats"
 | 
			
		||||
  voted: "Voté"
 | 
			
		||||
@@ -500,6 +433,11 @@ common/views/components/poll-editor.vue:
 | 
			
		||||
  remove: "Supprimer ce choix"
 | 
			
		||||
  add: "+ Ajouter un choix"
 | 
			
		||||
  destroy: "Annuler ce sondage"
 | 
			
		||||
  interval: "Durée"
 | 
			
		||||
  unit: "Unité"
 | 
			
		||||
  second: "secondes"
 | 
			
		||||
  minute: "Minutes"
 | 
			
		||||
  day: "D"
 | 
			
		||||
common/views/components/reaction-picker.vue:
 | 
			
		||||
  choose-reaction: "Choisissez votre réaction"
 | 
			
		||||
common/views/components/emoji-picker.vue:
 | 
			
		||||
@@ -629,11 +567,13 @@ common/views/components/profile-editor.vue:
 | 
			
		||||
  email-verified: "L’adresse du courrier électronique a été vérifiée."
 | 
			
		||||
  email-not-verified: "Adresse de courriel n’est pas confirmée. Veuillez vérifier votre boite de réception."
 | 
			
		||||
  export: "Exporter"
 | 
			
		||||
  import: "Importer"
 | 
			
		||||
  export-targets:
 | 
			
		||||
    all-notes: "Toutes les notes publiées"
 | 
			
		||||
    following-list: "Liste des abonnements"
 | 
			
		||||
    mute-list: "Liste des comptes mis en sourdine"
 | 
			
		||||
    blocking-list: "Liste des comptes bloqués"
 | 
			
		||||
    user-lists: "Listes"
 | 
			
		||||
  export-requested: "Vous avez demandé une exportation. Cela peut prendre un certain temps. Une fois l'exportation terminée, le fichier résultant sera ajouté dans le Drive."
 | 
			
		||||
  enter-password: "Veuillez saisir votre mot de passe"
 | 
			
		||||
  danger-zone: "Zone de danger"
 | 
			
		||||
@@ -695,7 +635,6 @@ common/views/widgets/tips.vue:
 | 
			
		||||
  tips-line19: "Plusieurs fenêtres peuvent être détachées en dehors du navigateur."
 | 
			
		||||
  tips-line20: "Pourcentage sur le widget calendrier qui indique le pourcentage de temps passé"
 | 
			
		||||
  tips-line21: "Vous pouvez aussi utiliser l'API pour développer des Bots."
 | 
			
		||||
  tips-line23: "藍かわいいよ藍"
 | 
			
		||||
  tips-line24: "Misskey est fonctionnel depuis 2014"
 | 
			
		||||
  tips-line25: "Vous pouvez recevoir les notifications de Misskey dans un navigateur web compatible"
 | 
			
		||||
common/views/pages/not-found.vue:
 | 
			
		||||
@@ -816,10 +755,6 @@ desktop/views/components/home.vue:
 | 
			
		||||
desktop/views/input-dialog.vue:
 | 
			
		||||
  cancel: "Annuler"
 | 
			
		||||
  ok: "OK"
 | 
			
		||||
desktop/views/components/messaging-room-window.vue:
 | 
			
		||||
  title: "Messages :"
 | 
			
		||||
desktop/views/components/messaging-window.vue:
 | 
			
		||||
  title: "Messagerie"
 | 
			
		||||
desktop/views/components/note-detail.vue:
 | 
			
		||||
  private: "cette publication est privée"
 | 
			
		||||
  deleted: "cette publication a été supprimée"
 | 
			
		||||
@@ -969,7 +904,7 @@ desktop/views/components/timeline.vue:
 | 
			
		||||
  hybrid: "Social"
 | 
			
		||||
  global: "Global"
 | 
			
		||||
  mentions: "Mentions"
 | 
			
		||||
  messages: "Messages"
 | 
			
		||||
  messages: "Messages directs"
 | 
			
		||||
  list: "Listes"
 | 
			
		||||
  hashtag: "Hashtag"
 | 
			
		||||
  add-tag-timeline: "Ajouter un fil de hashtags"
 | 
			
		||||
@@ -1023,7 +958,6 @@ admin/views/index.vue:
 | 
			
		||||
  hashtags: "Hashtags"
 | 
			
		||||
  abuse: "Abus"
 | 
			
		||||
  queue: "File d’attente"
 | 
			
		||||
  logs: "ログ"
 | 
			
		||||
  back-to-misskey: "Retour vers Misskey"
 | 
			
		||||
admin/views/dashboard.vue:
 | 
			
		||||
  dashboard: "Tableau de bord"
 | 
			
		||||
@@ -1034,7 +968,7 @@ admin/views/dashboard.vue:
 | 
			
		||||
  this-instance: "Cette instance"
 | 
			
		||||
  federated: "Fédérées"
 | 
			
		||||
admin/views/queue.vue:
 | 
			
		||||
  operation: "Action(s)"
 | 
			
		||||
  title: "File d'attente"
 | 
			
		||||
  remove-all-jobs: "Enlever toutes les tâches en attente"
 | 
			
		||||
admin/views/abuse.vue:
 | 
			
		||||
  title: "Abus"
 | 
			
		||||
@@ -1056,7 +990,6 @@ admin/views/instance.vue:
 | 
			
		||||
  maintainer-email: "Contact administratif"
 | 
			
		||||
  drive-config: "Paramètres du lecteur"
 | 
			
		||||
  cache-remote-files: "Mettre en cache des fichiers distants"
 | 
			
		||||
  cache-remote-files-desc: "この設定を無効にすると、リモートファイルをキャッシュせず直リンクするようになります。そのためサーバーのストレージを節約できますが、プライバシー設定で直リンクを無効にしているユーザーにはファイルが見えなくなったり、サムネイルが生成されないので通信量が増加します。通常はこの設定をオンにしておくことをおすすめします。"
 | 
			
		||||
  local-drive-capacity-mb: "Volume du lecteur par utilisateur"
 | 
			
		||||
  remote-drive-capacity-mb: "Volume du lecteur par utilisateur distant"
 | 
			
		||||
  mb: "en mégaoctets"
 | 
			
		||||
@@ -1081,7 +1014,6 @@ admin/views/instance.vue:
 | 
			
		||||
  discord-integration-client-id: "ID client"
 | 
			
		||||
  discord-integration-client-secret: "Secret client"
 | 
			
		||||
  proxy-account-config: "Compte proxy"
 | 
			
		||||
  proxy-account-info: "プロキシアカウントは、特定の条件下でユーザーのリモートフォローを代行するアカウントです。例えば、ユーザーがリモートユーザーをリストに入れたとき、リストに入れられたユーザーを誰もフォローしていないとアクティビティがサーバーに配達されないため、代わりにプロキシアカウントがフォローするようにします。"
 | 
			
		||||
  proxy-account-username: "Nom d’utilisateur du compte proxy"
 | 
			
		||||
  proxy-account-username-desc: "Spécifiez le nom d’utilisateur du compte utilisé comme proxy."
 | 
			
		||||
  proxy-account-warn: "Avant d’entamer cette action, vous devez au préalable avoir créé un compte avec ce nom d’utilisateur."
 | 
			
		||||
@@ -1252,47 +1184,39 @@ admin/views/announcements.vue:
 | 
			
		||||
admin/views/hashtags.vue:
 | 
			
		||||
  hided-tags: "Tags cachés"
 | 
			
		||||
admin/views/federation.vue:
 | 
			
		||||
  federation: "Fédération"
 | 
			
		||||
  instance: "Instance"
 | 
			
		||||
  host: "Hôte"
 | 
			
		||||
  notes: "Notes"
 | 
			
		||||
  users: "Utilisateur·rice·s"
 | 
			
		||||
  following: "Abonnements"
 | 
			
		||||
  followers: "Abonné·e·s"
 | 
			
		||||
  caught-at: "Créé le"
 | 
			
		||||
  status: "Statuts"
 | 
			
		||||
  latest-request-sent-at: "Dernière requête envoyée"
 | 
			
		||||
  latest-request-received-at: "Dernière requête reçue"
 | 
			
		||||
  remove-all-following: "フォローを全解除"
 | 
			
		||||
  remove-all-following-info: "Se désabonner de tous les comptes de {host}. Exécutez cette commande si l'instance n'existe plus."
 | 
			
		||||
  block: "Bloquer"
 | 
			
		||||
  marked-as-closed: "Marquées comme fermées"
 | 
			
		||||
  lookup: "Recherche"
 | 
			
		||||
  instances: "Instances"
 | 
			
		||||
  instance-not-registered: "そのインスタンスは登録されていません"
 | 
			
		||||
  instances: "Fédérées"
 | 
			
		||||
  sort: "Trier par"
 | 
			
		||||
  sorts:
 | 
			
		||||
    caughtAtAsc: "Date d’inscription (Ascendant)"
 | 
			
		||||
    caughtAtDesc: "Date d’inscription (Descendant)"
 | 
			
		||||
    lastCommunicatedAtAsc: "La date et l'heure des interactions plus anciennes"
 | 
			
		||||
    lastCommunicatedAtDesc: "La date et l'heure des nouvelles interactions"
 | 
			
		||||
    notesAsc: "投稿が少ない順"
 | 
			
		||||
    notesDesc: "Description des notes"
 | 
			
		||||
    usersAsc: "ユーザーが少ない順"
 | 
			
		||||
    usersDesc: "ユーザーが多い順"
 | 
			
		||||
    followingAsc: "Les moins suivies"
 | 
			
		||||
    followingDesc: "Ayant le plus d'abonné·e·s"
 | 
			
		||||
    followersAsc: "Ayant le moins d'abonné·e·s"
 | 
			
		||||
    followersDesc: "Ayant le plus d'abonné·e·s"
 | 
			
		||||
    driveUsageAsc: "Moins d'espace de stockage utilisé"
 | 
			
		||||
    driveUsageDesc: "ドライブ使用量が多い順"
 | 
			
		||||
    driveFilesAsc: "ドライブのファイル数が少ない順"
 | 
			
		||||
    driveFilesDesc: "ドライブのファイル数が多い順"
 | 
			
		||||
  state: "État"
 | 
			
		||||
  states:
 | 
			
		||||
    all: "Tout"
 | 
			
		||||
    blocked: "Bloquées"
 | 
			
		||||
    not-responding: "Sans réponse"
 | 
			
		||||
    marked-as-closed: "Marquée comme fermée"
 | 
			
		||||
  result-is-truncated: "上位{n}件を表示しています。"
 | 
			
		||||
  charts: "Graphs"
 | 
			
		||||
  chart-srcs:
 | 
			
		||||
    requests: "Requêtes"
 | 
			
		||||
@@ -1301,10 +1225,8 @@ admin/views/federation.vue:
 | 
			
		||||
    notes: "Augmentation/diminution du nombre des notes"
 | 
			
		||||
    notes-total: "Nombre total des notes"
 | 
			
		||||
    ff: "Augmentation des abonné·e·s"
 | 
			
		||||
    ff-total: "フォロー/フォロワーの積算"
 | 
			
		||||
    drive-usage: "Augmentation et diminution de la capacité stockage"
 | 
			
		||||
    drive-usage-total: "Utilisation totale du stockage"
 | 
			
		||||
    drive-files: "ドライブファイル数の増減"
 | 
			
		||||
    drive-files-total: "Nombre total des fichiers sur le Drive"
 | 
			
		||||
  chart-spans:
 | 
			
		||||
    hour: "Par heure"
 | 
			
		||||
@@ -1329,8 +1251,6 @@ desktop/views/pages/selectdrive.vue:
 | 
			
		||||
desktop/views/pages/search.vue:
 | 
			
		||||
  not-available: "La fonction de recherche est désactivée dans les paramètres de l’instance."
 | 
			
		||||
  not-found: "Aucune publication trouvée pour « {q} »."
 | 
			
		||||
desktop/views/pages/share.vue:
 | 
			
		||||
  share-with: "Partager avec {name}"
 | 
			
		||||
desktop/views/pages/tag.vue:
 | 
			
		||||
  no-posts-found: "Aucune publication contenant « {q} » n’a été trouvée."
 | 
			
		||||
desktop/views/pages/user-list.users.vue:
 | 
			
		||||
@@ -1365,8 +1285,6 @@ desktop/views/pages/user/user.timeline.vue:
 | 
			
		||||
  with-replies: "Publications et réponses"
 | 
			
		||||
  with-media: "Média"
 | 
			
		||||
  my-posts: "Mes Messages"
 | 
			
		||||
desktop/views/widgets/messaging.vue:
 | 
			
		||||
  title: "Messagerie"
 | 
			
		||||
desktop/views/widgets/notifications.vue:
 | 
			
		||||
  title: "Notifications"
 | 
			
		||||
desktop/views/widgets/polls.vue:
 | 
			
		||||
@@ -1397,7 +1315,6 @@ mobile/views/components/drive.vue:
 | 
			
		||||
  prompt: "Que veux-tu faire ? (Entrez un nombre): <1 → Télécharger le fichier | 2 → Télécharger le fichier avec l'URL | 3 → Créer le dossier | 4 → Modifier le nom du dossier | 5 → Déplacer ce dossier | 6 → Supprimer ce dossier >"
 | 
			
		||||
  deletion-alert: "Désolé ! La suppression d’un dossier n’est pas encore implémentée."
 | 
			
		||||
  folder-name: "Nom du dossier"
 | 
			
		||||
  here-is-root: "現在いる場所はルートで、フォルダではありません。"
 | 
			
		||||
  url-prompt: "URL du fichier que vous souhaitez téléverser"
 | 
			
		||||
  uploading: "Envoi demandé. Le téléversement pourrait prendre un certain temps avant de s'achever."
 | 
			
		||||
mobile/views/components/drive-file-chooser.vue:
 | 
			
		||||
@@ -1488,14 +1405,13 @@ mobile/views/pages/home.vue:
 | 
			
		||||
  hybrid: "Social"
 | 
			
		||||
  global: "Global"
 | 
			
		||||
  mentions: "Mentions"
 | 
			
		||||
  messages: "Messages"
 | 
			
		||||
  messages: "Messages directs"
 | 
			
		||||
mobile/views/pages/tag.vue:
 | 
			
		||||
  no-posts-found: "Aucune publication ayant pour hashtag « {q} » n’a été trouvée."
 | 
			
		||||
mobile/views/pages/widgets.vue:
 | 
			
		||||
  dashboard: "ダッシュボード"
 | 
			
		||||
  widgets-hints: "ウィジェットを追加/削除したり並べ替えたりできます。ウィジェットを移動するには「三」をドラッグします。ウィジェットを削除するには「x」をタップします。いくつかのウィジェットはタップすることで表示を変更できます。"
 | 
			
		||||
  add-widget: "追加"
 | 
			
		||||
  customization-tips: "カスタマイズのヒント"
 | 
			
		||||
  dashboard: "Tableau de bord"
 | 
			
		||||
  add-widget: "Ajouter"
 | 
			
		||||
  customization-tips: "Conseils de personnalisation"
 | 
			
		||||
mobile/views/pages/widgets/activity.vue:
 | 
			
		||||
  activity: "Activité"
 | 
			
		||||
mobile/views/pages/share.vue:
 | 
			
		||||
@@ -1548,7 +1464,7 @@ deck:
 | 
			
		||||
  direct: "Messages directs"
 | 
			
		||||
  notifications: "Notifications"
 | 
			
		||||
  list: "Listes"
 | 
			
		||||
  select-list: "リストを選択してください"
 | 
			
		||||
  select-list: "Sélectionnez une liste"
 | 
			
		||||
  swap-left: "Déplacer à gauche"
 | 
			
		||||
  swap-right: "Déplacer à droite"
 | 
			
		||||
  swap-up: "Déplacer vers le haut"
 | 
			
		||||
 
 | 
			
		||||
@@ -5,22 +5,49 @@
 | 
			
		||||
const fs = require('fs');
 | 
			
		||||
const yaml = require('js-yaml');
 | 
			
		||||
 | 
			
		||||
const langs = ['de-DE', 'en-US', 'fr-FR', 'ja-JP', 'ja-KS', 'pl-PL', 'es-ES', 'nl-NL', 'zh-CN', 'ko-KR'];
 | 
			
		||||
const merge = (...args) => args.reduce((a, c) => ({
 | 
			
		||||
	...a,
 | 
			
		||||
	...c,
 | 
			
		||||
	...Object.entries(a)
 | 
			
		||||
		.filter(([k]) => c && typeof c[k] === 'object')
 | 
			
		||||
		.reduce((a, [k, v]) => (a[k] = merge(v, c[k]), a), {})
 | 
			
		||||
}), {});
 | 
			
		||||
 | 
			
		||||
const loadLocale = lang => yaml.safeLoad(fs.readFileSync(`${__dirname}/${lang}.yml`, 'utf-8'));
 | 
			
		||||
const locales = langs
 | 
			
		||||
	.map(lang => [lang, loadLocale(lang)])
 | 
			
		||||
	.map(([lang, locale], _, locales) => {
 | 
			
		||||
		switch (lang) {
 | 
			
		||||
			case 'ja-JP': return [lang, locale];
 | 
			
		||||
			case 'en-US': return [lang, { ...locales['ja-JP'], ...locale }];
 | 
			
		||||
			default: return [lang, {
 | 
			
		||||
				...(lang.startsWith('ja-') ? {} : locales['en-US']),
 | 
			
		||||
				...locales['ja-JP'],
 | 
			
		||||
				...locale
 | 
			
		||||
		}];
 | 
			
		||||
const languages = [
 | 
			
		||||
	'cs-CZ',
 | 
			
		||||
	'de-DE',
 | 
			
		||||
	'en-US',
 | 
			
		||||
	'es-ES',
 | 
			
		||||
	'fr-FR',
 | 
			
		||||
	'ja-JP',
 | 
			
		||||
	'ja-KS',
 | 
			
		||||
	'ko-KR',
 | 
			
		||||
	'nl-NL',
 | 
			
		||||
	'pl-PL',
 | 
			
		||||
	'zh-CN',
 | 
			
		||||
	'zh-TW',
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const primaries = {
 | 
			
		||||
	'en': 'US',
 | 
			
		||||
	'ja': 'JP',
 | 
			
		||||
	'zh': 'CN',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const locales = languages.reduce((a, c) => (a[c] = yaml.safeLoad(fs.readFileSync(`${__dirname}/${c}.yml`, 'utf-8')) || {}, a), {});
 | 
			
		||||
 | 
			
		||||
module.exports = Object.entries(locales)
 | 
			
		||||
	.reduce((a, [k ,v]) => (a[k] = (() => {
 | 
			
		||||
		const [lang] = k.split('-');
 | 
			
		||||
		switch (k) {
 | 
			
		||||
			case 'ja-JP': return v;
 | 
			
		||||
			case 'ja-KS':
 | 
			
		||||
			case 'en-US': return merge(locales['ja-JP'], v);
 | 
			
		||||
			default: return merge(
 | 
			
		||||
				locales['ja-JP'],
 | 
			
		||||
				locales['en-US'],
 | 
			
		||||
				locales[`${lang}-${primaries[lang]}`] || {},
 | 
			
		||||
				v
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	.map(([lang, locale]) => ({ [lang]: loadLocale(lang) }));
 | 
			
		||||
 | 
			
		||||
module.exports = locales.reduce((a, b) => ({ ...a, ...b }));
 | 
			
		||||
	})(), a), {});
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1621
									
								
								locales/it-IT.yml
									
									
									
									
									
								
							
							
						
						
									
										1621
									
								
								locales/it-IT.yml
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -334,6 +334,7 @@ common/views/pages/explore.vue:
 | 
			
		||||
 | 
			
		||||
common/views/components/url-preview.vue:
 | 
			
		||||
  enable-player: "プレイヤーを開く"
 | 
			
		||||
  disable-player: "プレイヤーを閉じる"
 | 
			
		||||
 | 
			
		||||
common/views/components/user-list.vue:
 | 
			
		||||
  no-users: "ユーザーがいません"
 | 
			
		||||
@@ -512,8 +513,12 @@ common/views/components/user-menu.vue:
 | 
			
		||||
  mention: "メンション"
 | 
			
		||||
  mute: "ミュート"
 | 
			
		||||
  unmute: "ミュート解除"
 | 
			
		||||
  mute-confirm: "このユーザーをミュートしますか?"
 | 
			
		||||
  unmute-confirm: "このユーザーをミュート解除しますか?"
 | 
			
		||||
  block: "ブロック"
 | 
			
		||||
  unblock: "ブロック解除"
 | 
			
		||||
  block-confirm: "このユーザーをブロックしますか?"
 | 
			
		||||
  unblock-confirm: "このユーザーをブロック解除しますか?"
 | 
			
		||||
  push-to-list: "リストに追加"
 | 
			
		||||
  select-list: "リストを選択してください"
 | 
			
		||||
  report-abuse: "スパムを報告"
 | 
			
		||||
@@ -521,16 +526,25 @@ common/views/components/user-menu.vue:
 | 
			
		||||
  report-abuse-reported: "管理者に報告されました。ご協力ありがとうございました。"
 | 
			
		||||
  silence: "サイレンス"
 | 
			
		||||
  unsilence: "サイレンス解除"
 | 
			
		||||
  silence-confirm: "このユーザーをサイレンスしますか?"
 | 
			
		||||
  unsilence-confirm: "このユーザーをサイレンス解除しますか?"
 | 
			
		||||
  suspend: "凍結"
 | 
			
		||||
  unsuspend: "凍結解除"
 | 
			
		||||
  suspend-confirm: "このユーザーを凍結しますか?"
 | 
			
		||||
  unsuspend-confirm: "このユーザーを凍結解除しますか?"
 | 
			
		||||
 | 
			
		||||
common/views/components/poll.vue:
 | 
			
		||||
  vote-to: "「{}」に投票する"
 | 
			
		||||
  vote-count: "{}票"
 | 
			
		||||
  total-users: "{}人が投票"
 | 
			
		||||
  total-votes: "計{}票"
 | 
			
		||||
  vote: "投票する"
 | 
			
		||||
  show-result: "結果を見る"
 | 
			
		||||
  voted: "投票済み"
 | 
			
		||||
  closed: "終了済み"
 | 
			
		||||
  remaining-days: "終了まであと{d}日{h}時間"
 | 
			
		||||
  remaining-hours: "終了まであと{h}時間{m}分"
 | 
			
		||||
  remaining-minutes: "終了まであと{m}分{s}秒"
 | 
			
		||||
  remaining-seconds: "終了まであと{s}秒"
 | 
			
		||||
 | 
			
		||||
common/views/components/poll-editor.vue:
 | 
			
		||||
  no-only-one-choice: "アンケートには、選択肢が最低2つ必要です"
 | 
			
		||||
@@ -538,6 +552,20 @@ common/views/components/poll-editor.vue:
 | 
			
		||||
  remove: "この選択肢を削除"
 | 
			
		||||
  add: "+選択肢を追加"
 | 
			
		||||
  destroy: "アンケートを破棄"
 | 
			
		||||
  multiple: "複数回答可"
 | 
			
		||||
  expiration: "期限"
 | 
			
		||||
  infinite: "無期限"
 | 
			
		||||
  at: "日時指定"
 | 
			
		||||
  after: "経過指定"
 | 
			
		||||
  no-more: "これ以上追加できません"
 | 
			
		||||
  deadline-date: "期日"
 | 
			
		||||
  deadline-time: "時間"
 | 
			
		||||
  interval: "期間"
 | 
			
		||||
  unit: "単位"
 | 
			
		||||
  second: "秒"
 | 
			
		||||
  minute: "分"
 | 
			
		||||
  hour: "時間"
 | 
			
		||||
  day: "日"
 | 
			
		||||
 | 
			
		||||
common/views/components/reaction-picker.vue:
 | 
			
		||||
  choose-reaction: "リアクションを選択"
 | 
			
		||||
@@ -682,12 +710,16 @@ common/views/components/profile-editor.vue:
 | 
			
		||||
  email-verified: "メールアドレスが確認されました"
 | 
			
		||||
  email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
 | 
			
		||||
  export: "エクスポート"
 | 
			
		||||
  import: "インポート"
 | 
			
		||||
  export-and-import: "エクスポートとインポート"
 | 
			
		||||
  export-targets:
 | 
			
		||||
    all-notes: "すべての投稿データ"
 | 
			
		||||
    following-list: "フォロー"
 | 
			
		||||
    mute-list: "ミュート"
 | 
			
		||||
    blocking-list: "ブロック"
 | 
			
		||||
    user-lists: "リスト"
 | 
			
		||||
  export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
 | 
			
		||||
  import-requested: "インポートをリクエストしました。これには時間がかかる場合があります。"
 | 
			
		||||
  enter-password: "パスワードを入力してください"
 | 
			
		||||
  danger-zone: "危険な設定"
 | 
			
		||||
  delete-account: "アカウントを削除"
 | 
			
		||||
@@ -901,12 +933,6 @@ desktop/views/input-dialog.vue:
 | 
			
		||||
  cancel: "キャンセル"
 | 
			
		||||
  ok: "決定"
 | 
			
		||||
 | 
			
		||||
desktop/views/components/messaging-room-window.vue:
 | 
			
		||||
  title: "メッセージ:"
 | 
			
		||||
 | 
			
		||||
desktop/views/components/messaging-window.vue:
 | 
			
		||||
  title: "メッセージ"
 | 
			
		||||
 | 
			
		||||
desktop/views/components/note-detail.vue:
 | 
			
		||||
  private: "この投稿は非公開です"
 | 
			
		||||
  deleted: "この投稿は削除されました"
 | 
			
		||||
@@ -949,7 +975,6 @@ desktop/views/components/post-form.vue:
 | 
			
		||||
  posting: "投稿中"
 | 
			
		||||
  attach-media-from-local: "PCからメディアを添付"
 | 
			
		||||
  attach-media-from-drive: "ドライブからメディアを添付"
 | 
			
		||||
  attach-cancel: "添付取り消し"
 | 
			
		||||
  insert-a-kao: "v('ω')v"
 | 
			
		||||
  create-poll: "アンケートを作成"
 | 
			
		||||
  text-remain: "残り{}文字"
 | 
			
		||||
@@ -1055,6 +1080,11 @@ common/views/components/password-settings.vue:
 | 
			
		||||
  changed: "パスワードを変更しました"
 | 
			
		||||
  failed: "パスワード変更に失敗しました"
 | 
			
		||||
 | 
			
		||||
common/views/components/post-form-attaches.vue:
 | 
			
		||||
  attach-cancel: "添付取り消し"
 | 
			
		||||
  mark-as-sensitive: "閲覧注意に設定"
 | 
			
		||||
  unmark-as-sensitive: "閲覧注意を解除"
 | 
			
		||||
 | 
			
		||||
desktop/views/components/sub-note-content.vue:
 | 
			
		||||
  private: "この投稿は非公開です"
 | 
			
		||||
  deleted: "この投稿は削除されました"
 | 
			
		||||
@@ -1076,7 +1106,7 @@ desktop/views/components/timeline.vue:
 | 
			
		||||
  hybrid: "ソーシャル"
 | 
			
		||||
  global: "グローバル"
 | 
			
		||||
  mentions: "あなた宛て"
 | 
			
		||||
  messages: "メッセージ"
 | 
			
		||||
  messages: "ダイレクト投稿"
 | 
			
		||||
  list: "リスト"
 | 
			
		||||
  hashtag: "ハッシュタグ"
 | 
			
		||||
  add-tag-timeline: "ハッシュタグを追加"
 | 
			
		||||
@@ -1156,7 +1186,7 @@ admin/views/dashboard.vue:
 | 
			
		||||
  federated: "連合"
 | 
			
		||||
 | 
			
		||||
admin/views/queue.vue:
 | 
			
		||||
  operation: "操作"
 | 
			
		||||
  title: "キュー"
 | 
			
		||||
  remove-all-jobs: "すべてのジョブをクリア"
 | 
			
		||||
 | 
			
		||||
admin/views/abuse.vue:
 | 
			
		||||
@@ -1214,6 +1244,8 @@ admin/views/instance.vue:
 | 
			
		||||
  disable-local-timeline: "ローカルタイムラインを無効にする"
 | 
			
		||||
  disable-global-timeline: "グローバルタイムラインを無効にする"
 | 
			
		||||
  disabling-timelines-info: "これらのタイムラインを無効にしても、管理者およびモデレーターは引き続き利用できます。"
 | 
			
		||||
  enable-emoji-reaction: "リアクションに絵文字を使えるようにする"
 | 
			
		||||
  use-star-for-reaction-fallback: "不明なリアクションのフォールバックに star を使う"
 | 
			
		||||
  invite: "招待"
 | 
			
		||||
  save: "保存"
 | 
			
		||||
  saved: "保存しました"
 | 
			
		||||
@@ -1306,7 +1338,9 @@ admin/views/users.vue:
 | 
			
		||||
  unsuspend-confirm: "凍結を解除しますか?"
 | 
			
		||||
  unsuspended: "凍結を解除しました"
 | 
			
		||||
  make-silence: "サイレンス"
 | 
			
		||||
  silence-confirm: "サイレンスしますか?"
 | 
			
		||||
  unmake-silence: "サイレンスの解除"
 | 
			
		||||
  unsilence-confirm: "サイレンスを解除しますか?"
 | 
			
		||||
  verify: "公式アカウントにする"
 | 
			
		||||
  verify-confirm: "公式アカウントにしますか?"
 | 
			
		||||
  verified: "公式アカウントにしました"
 | 
			
		||||
@@ -1384,12 +1418,13 @@ admin/views/hashtags.vue:
 | 
			
		||||
  hided-tags: "Hidden Tags"
 | 
			
		||||
 | 
			
		||||
admin/views/federation.vue:
 | 
			
		||||
  federation: "連合"
 | 
			
		||||
  instance: "インスタンス"
 | 
			
		||||
  host: "ホスト"
 | 
			
		||||
  notes: "投稿"
 | 
			
		||||
  users: "ユーザー"
 | 
			
		||||
  following: "フォロー中"
 | 
			
		||||
  followers: "フォロワー"
 | 
			
		||||
  caught-at: "登録日時"
 | 
			
		||||
  status: "ステータス"
 | 
			
		||||
  latest-request-sent-at: "直近のリクエスト送信"
 | 
			
		||||
  latest-request-received-at: "直近のリクエスト受信"
 | 
			
		||||
@@ -1398,7 +1433,7 @@ admin/views/federation.vue:
 | 
			
		||||
  block: "ブロック"
 | 
			
		||||
  marked-as-closed: "閉鎖されているとマーク"
 | 
			
		||||
  lookup: "照会"
 | 
			
		||||
  instances: "インスタンス"
 | 
			
		||||
  instances: "連合"
 | 
			
		||||
  instance-not-registered: "そのインスタンスは登録されていません"
 | 
			
		||||
  sort: "ソート"
 | 
			
		||||
  sorts:
 | 
			
		||||
@@ -1467,9 +1502,6 @@ desktop/views/pages/search.vue:
 | 
			
		||||
  not-available: "検索機能はインスタンスの設定で無効になっています。"
 | 
			
		||||
  not-found: "「{q}」に関する投稿は見つかりませんでした。"
 | 
			
		||||
 | 
			
		||||
desktop/views/pages/share.vue:
 | 
			
		||||
  share-with: "{name}で共有"
 | 
			
		||||
 | 
			
		||||
desktop/views/pages/tag.vue:
 | 
			
		||||
  no-posts-found: "ハッシュタグ「{q}」が付けられた投稿は見つかりませんでした。"
 | 
			
		||||
 | 
			
		||||
@@ -1511,9 +1543,6 @@ desktop/views/pages/user/user.timeline.vue:
 | 
			
		||||
  with-media: "メディア"
 | 
			
		||||
  my-posts: "私の投稿"
 | 
			
		||||
 | 
			
		||||
desktop/views/widgets/messaging.vue:
 | 
			
		||||
  title: "メッセージ"
 | 
			
		||||
 | 
			
		||||
desktop/views/widgets/notifications.vue:
 | 
			
		||||
  title: "通知"
 | 
			
		||||
 | 
			
		||||
@@ -1661,7 +1690,7 @@ mobile/views/pages/home.vue:
 | 
			
		||||
  hybrid: "ソーシャル"
 | 
			
		||||
  global: "グローバル"
 | 
			
		||||
  mentions: "あなた宛て"
 | 
			
		||||
  messages: "メッセージ"
 | 
			
		||||
  messages: "ダイレクト投稿"
 | 
			
		||||
 | 
			
		||||
mobile/views/pages/tag.vue:
 | 
			
		||||
  no-posts-found: "ハッシュタグ「{q}」が付けられた投稿は見つかりませんでした。"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
---
 | 
			
		||||
meta:
 | 
			
		||||
  lang: "日本語 (関西弁)"
 | 
			
		||||
  divider: ""
 | 
			
		||||
common:
 | 
			
		||||
  misskey: "A ⭐ of fediverse"
 | 
			
		||||
  about-title: "A ⭐ of fediverse."
 | 
			
		||||
@@ -28,13 +27,6 @@ common:
 | 
			
		||||
  load-more: "もっとあらへんのか!"
 | 
			
		||||
  enter-password: "パスワードを入れてや"
 | 
			
		||||
  2fa: "二段階認証"
 | 
			
		||||
  customize-home: "ホームをカスタマイズ"
 | 
			
		||||
  featured-notes: "ハイライト"
 | 
			
		||||
  dark-mode: "ダークモード"
 | 
			
		||||
  signin: "ログイン"
 | 
			
		||||
  signup: "新規登録"
 | 
			
		||||
  signout: "ログアウト"
 | 
			
		||||
  reload-to-apply-the-setting: "この設定を反映するにはページをリロードする必要があります。今すぐリロードしますか?"
 | 
			
		||||
  got-it: "ほい"
 | 
			
		||||
  customization-tips:
 | 
			
		||||
    title: "カスタマイズのヒント"
 | 
			
		||||
@@ -64,15 +56,10 @@ common:
 | 
			
		||||
  drive: "ドライブ"
 | 
			
		||||
  messaging: "トーク"
 | 
			
		||||
  home: "ホーム"
 | 
			
		||||
  deck: "デッキ"
 | 
			
		||||
  timeline: "タイムライン"
 | 
			
		||||
  explore: "みつける"
 | 
			
		||||
  following: "フォロー中"
 | 
			
		||||
  following: "フォローしとる"
 | 
			
		||||
  followers: "フォロワー"
 | 
			
		||||
  favorites: "お気に入り"
 | 
			
		||||
  empty-timeline-info:
 | 
			
		||||
    follow-users-to-make-your-timeline: "ユーザーをフォローすると投稿がタイムラインに表示されます。"
 | 
			
		||||
    explore: "ユーザーを探索する"
 | 
			
		||||
  weekday-short:
 | 
			
		||||
    sunday: "日"
 | 
			
		||||
    monday: "月"
 | 
			
		||||
@@ -118,129 +105,25 @@ common:
 | 
			
		||||
    d: "言うときたいことは?"
 | 
			
		||||
    e: "ここに書いてや"
 | 
			
		||||
    f: "あんさんが書くんを待っちょります..."
 | 
			
		||||
  settings: "設定"
 | 
			
		||||
  _settings:
 | 
			
		||||
    profile: "プロフィール"
 | 
			
		||||
    notification: "通知"
 | 
			
		||||
    apps: "アプリ"
 | 
			
		||||
    tags: "ハッシュタグ"
 | 
			
		||||
    mute-and-block: "ミュート/ブロック"
 | 
			
		||||
    blocking: "ブロック"
 | 
			
		||||
    security: "セキュリティ"
 | 
			
		||||
    signin: "ログイン履歴"
 | 
			
		||||
    password: "パスワード"
 | 
			
		||||
    other: "その他"
 | 
			
		||||
    appearance: "デザイン"
 | 
			
		||||
    behavior: "動作"
 | 
			
		||||
    fetch-on-scroll: "スクロールで自動読み込み"
 | 
			
		||||
    fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。"
 | 
			
		||||
    note-visibility: "投稿の公開範囲"
 | 
			
		||||
    default-note-visibility: "デフォルトの公開範囲"
 | 
			
		||||
    remember-note-visibility: "投稿の公開範囲を記憶する"
 | 
			
		||||
    web-search-engine: "ウェブ検索エンジン"
 | 
			
		||||
    web-search-engine-desc: "例: https://www.google.com/?#q={{query}}"
 | 
			
		||||
    keep-cw: "CW保持"
 | 
			
		||||
    keep-cw-desc: "投稿にリプライする際、リプライ元の投稿にCWが設定されていたとき、デフォルトで同じCWを設定するようにします。"
 | 
			
		||||
    i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
 | 
			
		||||
    show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示"
 | 
			
		||||
    use-avatar-reversi-stones: "リバーシの石にアバターを使う"
 | 
			
		||||
    disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
 | 
			
		||||
    disable-showing-animated-images: "アニメーション画像を再生しない"
 | 
			
		||||
    suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する"
 | 
			
		||||
    always-show-nsfw: "常に閲覧注意のメディアを表示する"
 | 
			
		||||
    always-mark-nsfw: "常にメディアを閲覧注意として投稿"
 | 
			
		||||
    show-full-acct: "ユーザー名のホストを省略しない"
 | 
			
		||||
    show-via: "viaを表示する"
 | 
			
		||||
    reduce-motion: "UIの動きを減らす"
 | 
			
		||||
    this-setting-is-this-device-only: "このデバイスのみ"
 | 
			
		||||
    use-os-default-emojis: "OS標準の絵文字を使用"
 | 
			
		||||
    line-width: "線の太さ"
 | 
			
		||||
    line-width-thin: "細い"
 | 
			
		||||
    line-width-normal: "普通"
 | 
			
		||||
    line-width-thick: "太い"
 | 
			
		||||
    font-size: "文字の大きさ"
 | 
			
		||||
    font-size-x-small: "小さい"
 | 
			
		||||
    font-size-small: "少し小さい"
 | 
			
		||||
    font-size-medium: "普通"
 | 
			
		||||
    font-size-large: "少し大きい"
 | 
			
		||||
    font-size-x-large: "大きい"
 | 
			
		||||
    deck-column-align: "デッキのカラムの配置"
 | 
			
		||||
    deck-column-align-center: "中央"
 | 
			
		||||
    deck-column-align-left: "左"
 | 
			
		||||
    deck-column-align-flexible: "フレキシブル"
 | 
			
		||||
    deck-column-width: "デッキのカラムの幅"
 | 
			
		||||
    deck-column-width-narrow: "狭"
 | 
			
		||||
    deck-column-width-narrower: "やや狭"
 | 
			
		||||
    deck-column-width-normal: "普通"
 | 
			
		||||
    deck-column-width-wider: "やや広"
 | 
			
		||||
    deck-column-width-wide: "広"
 | 
			
		||||
    use-shadow: "UIに影を使用"
 | 
			
		||||
    rounded-corners: "UIの角を丸める"
 | 
			
		||||
    circle-icons: "円形のアイコンを使用"
 | 
			
		||||
    contrasted-acct: "ユーザー名にコントラストを付ける"
 | 
			
		||||
    wallpaper: "壁紙"
 | 
			
		||||
    choose-wallpaper: "壁紙を選択"
 | 
			
		||||
    delete-wallpaper: "壁紙を削除"
 | 
			
		||||
    post-form-on-timeline: "タイムライン上部に投稿フォームを表示する"
 | 
			
		||||
    show-clock-on-header: "右上に時計を表示する"
 | 
			
		||||
    show-reply-target: "リプライ先を表示する"
 | 
			
		||||
    timeline: "タイムライン"
 | 
			
		||||
    show-my-renotes: "自分の行ったRenoteをタイムラインに表示する"
 | 
			
		||||
    show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する"
 | 
			
		||||
    show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する"
 | 
			
		||||
    remain-deleted-note: "削除された投稿を表示し続ける"
 | 
			
		||||
    sound: "サウンド"
 | 
			
		||||
    enable-sounds: "サウンドを有効にする"
 | 
			
		||||
    enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
 | 
			
		||||
    volume: "ボリューム"
 | 
			
		||||
    test: "テスト"
 | 
			
		||||
    update: "Misskey Update"
 | 
			
		||||
    version: "バージョン:"
 | 
			
		||||
    latest-version: "最新のバージョン:"
 | 
			
		||||
    update-checking: "アップデートを確認中"
 | 
			
		||||
    do-update: "アップデートを確認"
 | 
			
		||||
    update-settings: "詳細設定"
 | 
			
		||||
    no-updates: "利用可能な更新はありません"
 | 
			
		||||
    no-updates-desc: "お使いのMisskeyは最新です。"
 | 
			
		||||
    update-available: "新しいバージョンが利用可能です"
 | 
			
		||||
    update-available-desc: "ページを再度読み込みすると更新が適用されます。"
 | 
			
		||||
    advanced-settings: "高度な設定"
 | 
			
		||||
    debug-mode: "デバッグモードを有効にする"
 | 
			
		||||
    debug-mode-desc: "この設定はブラウザに記憶されます。"
 | 
			
		||||
    navbar-position: "ナビゲーションバーの位置"
 | 
			
		||||
    navbar-position-top: "上"
 | 
			
		||||
    navbar-position-left: "左"
 | 
			
		||||
    navbar-position-right: "右"
 | 
			
		||||
    i-am-under-limited-internet: "私は通信を制限されている"
 | 
			
		||||
    post-style: "投稿の表示スタイル"
 | 
			
		||||
    post-style-standard: "標準"
 | 
			
		||||
    post-style-smart: "スマート"
 | 
			
		||||
    notification-position: "通知の表示"
 | 
			
		||||
    notification-position-bottom: "下"
 | 
			
		||||
    notification-position-top: "上"
 | 
			
		||||
    disable-via-mobile: "「モバイルからの投稿」フラグを付けない"
 | 
			
		||||
    load-raw-images: "添付された画像を高画質で表示する"
 | 
			
		||||
    load-remote-media: "リモートサーバーのメディアを表示する"
 | 
			
		||||
  search: "検索"
 | 
			
		||||
  delete: "削除"
 | 
			
		||||
  loading: "読み込み中"
 | 
			
		||||
  ok: "おk"
 | 
			
		||||
  cancel: "やめる"
 | 
			
		||||
  update-available-title: "更新があんで"
 | 
			
		||||
  update-available: "Misskeyの新しいバージョンがあんで({newer}。現在{current}をつこてるわ)。ページを再度読み込みしたると更新が適用されるわ。"
 | 
			
		||||
  my-token-regenerated: "あんさんのトークンが更新されたらしいわ。すまんがとりあえずサインアウトすんで。"
 | 
			
		||||
  verified-user: "アメちゃん付きアカウント"
 | 
			
		||||
  hide-password: "パスワードを隠す"
 | 
			
		||||
  show-password: "パスワードを表示する"
 | 
			
		||||
  do-not-use-in-production: "開発ビルドや。本番環境で使わんといて!知らんで!"
 | 
			
		||||
  user-suspended: "このユーザーは凍結されています。"
 | 
			
		||||
  is-remote-user: "このユーザー情報は不正確な可能性があります。"
 | 
			
		||||
  is-remote-post: "この投稿情報はコピーです。"
 | 
			
		||||
  view-on-remote: "ちゃんとした情報見せてや!"
 | 
			
		||||
  renoted-by: "{user}がRenote"
 | 
			
		||||
  no-notes: "投稿がありません"
 | 
			
		||||
  turn-on-darkmode: "闇に飲まれる"
 | 
			
		||||
  turn-off-darkmode: "光あれ"
 | 
			
		||||
  error:
 | 
			
		||||
    title: "問題が起こったわ"
 | 
			
		||||
    retry: "もっぺん"
 | 
			
		||||
@@ -279,7 +162,7 @@ common:
 | 
			
		||||
    hashtags: "ハッシュタグ"
 | 
			
		||||
  dev: "アプリの作成あかんかったわ。もっぺんやってみて。"
 | 
			
		||||
  ai-chan-kawaii: "藍ちゃめっさべっぴんさんや"
 | 
			
		||||
  you: "あなた"
 | 
			
		||||
  you: "あんさん"
 | 
			
		||||
auth/views/form.vue:
 | 
			
		||||
  share-access: "あんたのアカウントに<i>{name}</i>がアクセスしようとしてるで?ええか?"
 | 
			
		||||
  permission-ask: "このアプリは次の権限を要求してんで:"
 | 
			
		||||
@@ -305,18 +188,8 @@ auth/views/index.vue:
 | 
			
		||||
  error: "セッションが存在してへん。"
 | 
			
		||||
  sign-in: "サインインしてや"
 | 
			
		||||
common/views/pages/explore.vue:
 | 
			
		||||
  verified-users: "公式アカウント"
 | 
			
		||||
  popular-users: "人気のユーザー"
 | 
			
		||||
  recently-updated-users: "最近投稿したユーザー"
 | 
			
		||||
  recently-registered-users: "新規ユーザー"
 | 
			
		||||
  popular-tags: "人気のタグ"
 | 
			
		||||
  verified-users: "アメちゃん付きアカウント"
 | 
			
		||||
  federated: "連合"
 | 
			
		||||
  explore: "{host}を探索"
 | 
			
		||||
  users-info: "現在{users}ユーザーが登録されています"
 | 
			
		||||
common/views/components/url-preview.vue:
 | 
			
		||||
  enable-player: "プレイヤーを開く"
 | 
			
		||||
common/views/components/user-list.vue:
 | 
			
		||||
  no-users: "ユーザーがいません"
 | 
			
		||||
common/views/components/games/reversi/reversi.vue:
 | 
			
		||||
  matching:
 | 
			
		||||
    waiting-for: "{}を待っとります"
 | 
			
		||||
@@ -388,7 +261,6 @@ common/views/components/media-banner.vue:
 | 
			
		||||
  sensitive: "見せたらあかん"
 | 
			
		||||
  click-to-show: "押してみ、見せたるわ"
 | 
			
		||||
common/views/components/theme.vue:
 | 
			
		||||
  theme: "テーマ"
 | 
			
		||||
  light-theme: "ナイトゲームちゃう時のテーマどないする?"
 | 
			
		||||
  dark-theme: "ナイトゲームの時のテーマどないする?"
 | 
			
		||||
  light-themes: "デイゲーム"
 | 
			
		||||
@@ -405,7 +277,6 @@ common/views/components/theme.vue:
 | 
			
		||||
  base-theme: "この色が背景や!"
 | 
			
		||||
  base-theme-light: "Light"
 | 
			
		||||
  base-theme-dark: "Dark"
 | 
			
		||||
  find-more-theme: "その他のテーマを入手"
 | 
			
		||||
  theme-name: "テーマ名"
 | 
			
		||||
  preview-created-theme: "試してみる"
 | 
			
		||||
  invalid-theme: "このテーマあかんわ、なんか間違うとる"
 | 
			
		||||
@@ -427,8 +298,6 @@ common/views/components/theme.vue:
 | 
			
		||||
common/views/components/cw-button.vue:
 | 
			
		||||
  hide: "もうええわ"
 | 
			
		||||
  show: "見たいやろ?"
 | 
			
		||||
  chars: "{count}文字"
 | 
			
		||||
  files: "{count}ファイル"
 | 
			
		||||
  poll: "アンケート"
 | 
			
		||||
common/views/components/messaging.vue:
 | 
			
		||||
  search-user: "ユーザーを探す"
 | 
			
		||||
@@ -459,38 +328,22 @@ common/views/components/nav.vue:
 | 
			
		||||
  develop: "開発者"
 | 
			
		||||
  feedback: "フィードバック"
 | 
			
		||||
common/views/components/note-menu.vue:
 | 
			
		||||
  mention: "メンション"
 | 
			
		||||
  detail: "もっと"
 | 
			
		||||
  copy-content: "内容をコピー"
 | 
			
		||||
  copy-link: "リンクをコピー"
 | 
			
		||||
  favorite: "お気に入り"
 | 
			
		||||
  unfavorite: "お気に入りやめる"
 | 
			
		||||
  watch: "ウォッチ"
 | 
			
		||||
  unwatch: "ウォッチ解除"
 | 
			
		||||
  pin: "ピン留め"
 | 
			
		||||
  unpin: "ピン留めやめる"
 | 
			
		||||
  delete: "ほかす"
 | 
			
		||||
  delete-confirm: "この投稿を削除してもええか?"
 | 
			
		||||
  remote: "投稿元に行ってみよか"
 | 
			
		||||
common/views/components/user-menu.vue:
 | 
			
		||||
  mention: "メンション"
 | 
			
		||||
  mute: "ミュート"
 | 
			
		||||
  unmute: "ミュート解除"
 | 
			
		||||
  block: "ブロック"
 | 
			
		||||
  unblock: "ブロック解除"
 | 
			
		||||
  push-to-list: "リストに追加"
 | 
			
		||||
  select-list: "リストを選択してください"
 | 
			
		||||
  report-abuse: "スパムを報告"
 | 
			
		||||
  report-abuse-detail: "どのような迷惑行為を行っていますか?"
 | 
			
		||||
  report-abuse-reported: "管理者に報告されました。ご協力ありがとうございました。"
 | 
			
		||||
  silence: "サイレンス"
 | 
			
		||||
  unsilence: "サイレンス解除"
 | 
			
		||||
  suspend: "凍結"
 | 
			
		||||
  unsuspend: "凍結解除"
 | 
			
		||||
common/views/components/poll.vue:
 | 
			
		||||
  vote-to: "「{}」に投票や!"
 | 
			
		||||
  vote-count: "{}票"
 | 
			
		||||
  total-users: "{}人が投票"
 | 
			
		||||
  vote: "投票するで"
 | 
			
		||||
  show-result: "結果を見よか"
 | 
			
		||||
  voted: "投票済みや"
 | 
			
		||||
@@ -500,6 +353,7 @@ common/views/components/poll-editor.vue:
 | 
			
		||||
  remove: "この選択肢を消すで"
 | 
			
		||||
  add: "+選択肢を追加"
 | 
			
		||||
  destroy: "アンケートをほかそ"
 | 
			
		||||
  day: "日"
 | 
			
		||||
common/views/components/reaction-picker.vue:
 | 
			
		||||
  choose-reaction: "リアクション、どれにするんや?"
 | 
			
		||||
common/views/components/emoji-picker.vue:
 | 
			
		||||
@@ -554,11 +408,6 @@ common/views/components/stream-indicator.vue:
 | 
			
		||||
  connected: "つないだわ"
 | 
			
		||||
common/views/components/notification-settings.vue:
 | 
			
		||||
  title: "通知"
 | 
			
		||||
  mark-as-read-all-notifications: "すべての通知を既読にする"
 | 
			
		||||
  mark-as-read-all-unread-notes: "すべての投稿を既読にする"
 | 
			
		||||
  mark-as-read-all-talk-messages: "すべてのトークを既読にする"
 | 
			
		||||
  auto-watch: "投稿の自動ウォッチ"
 | 
			
		||||
  auto-watch-desc: "リアクションしたり返信したりした投稿に関する通知を自動的に受け取るようにします。"
 | 
			
		||||
common/views/components/integration-settings.vue:
 | 
			
		||||
  title: "サービス連携"
 | 
			
		||||
  connect: "つなげる"
 | 
			
		||||
@@ -608,7 +457,6 @@ common/views/components/profile-editor.vue:
 | 
			
		||||
  account: "アカウント"
 | 
			
		||||
  location: "場所"
 | 
			
		||||
  description: "自己紹介"
 | 
			
		||||
  you-can-include-hashtags: "ハッシュタグを含めることができます。"
 | 
			
		||||
  language: "言語"
 | 
			
		||||
  birthday: "誕生日"
 | 
			
		||||
  avatar: "アイコン"
 | 
			
		||||
@@ -617,7 +465,6 @@ common/views/components/profile-editor.vue:
 | 
			
		||||
  is-bot: "このアカウントはBotやで"
 | 
			
		||||
  is-locked: "他人のフォローは許可してからや!"
 | 
			
		||||
  careful-bot: "Botからのフォローだけは許可制や"
 | 
			
		||||
  auto-accept-followed: "フォローしているユーザーからのフォローを自動承認する"
 | 
			
		||||
  advanced: "その他"
 | 
			
		||||
  privacy: "プライバシーってなんや?オカンの年齢か?"
 | 
			
		||||
  save: "保存"
 | 
			
		||||
@@ -629,23 +476,15 @@ common/views/components/profile-editor.vue:
 | 
			
		||||
  email-verified: "このメールアドレスOKや!"
 | 
			
		||||
  email-not-verified: "メールアドレスが確認されとらん。メールボックスもっぺん見てくれへん?"
 | 
			
		||||
  export: "エクスポート"
 | 
			
		||||
  import: "インポート"
 | 
			
		||||
  export-targets:
 | 
			
		||||
    all-notes: "すべての投稿データ"
 | 
			
		||||
    following-list: "フォロー"
 | 
			
		||||
    mute-list: "ミュート"
 | 
			
		||||
    blocking-list: "ブロック"
 | 
			
		||||
  export-requested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、ドライブにファイルが追加されます。"
 | 
			
		||||
  enter-password: "パスワードを入力してください"
 | 
			
		||||
  danger-zone: "危険な設定"
 | 
			
		||||
  delete-account: "アカウントを削除"
 | 
			
		||||
  account-deleted: "アカウントが削除されました。データが消えるまで時間がかかる場合があります。"
 | 
			
		||||
    user-lists: "リスト"
 | 
			
		||||
  enter-password: "パスワードを入れてや"
 | 
			
		||||
common/views/components/user-list-editor.vue:
 | 
			
		||||
  users: "ユーザー"
 | 
			
		||||
  rename: "リスト名を変更"
 | 
			
		||||
  delete: "リストを削除"
 | 
			
		||||
  remove-user: "このリストから削除"
 | 
			
		||||
  delete-are-you-sure: "リスト「$1」を削除しますか?"
 | 
			
		||||
  deleted: "削除しました"
 | 
			
		||||
common/views/widgets/broadcast.vue:
 | 
			
		||||
  fetching: "見てみるわ…"
 | 
			
		||||
  no-broadcasts: "お知らせはあらへんで"
 | 
			
		||||
@@ -695,11 +534,8 @@ common/views/widgets/tips.vue:
 | 
			
		||||
  tips-line19: "いくつかのウィンドウはブラウザの外に切り離すことができんで"
 | 
			
		||||
  tips-line20: "カレンダーウィジェットのパーセンテージは、経過の割合を示してんねん"
 | 
			
		||||
  tips-line21: "APIをつこてbotの開発なども行えるで"
 | 
			
		||||
  tips-line23: "藍かわいいよ藍"
 | 
			
		||||
  tips-line24: "Misskeyは2014年にサービスを開始したんよ"
 | 
			
		||||
  tips-line25: "対応ブラウザやったらMisskeyを開いとらんでも通知を受け取れんで"
 | 
			
		||||
common/views/pages/not-found.vue:
 | 
			
		||||
  page-not-found: "ページが見つかりませんでした"
 | 
			
		||||
common/views/pages/follow.vue:
 | 
			
		||||
  signed-in-as: "{}としてサインイン中"
 | 
			
		||||
  following: "フォローしとる"
 | 
			
		||||
@@ -816,22 +652,16 @@ desktop/views/components/home.vue:
 | 
			
		||||
desktop/views/input-dialog.vue:
 | 
			
		||||
  cancel: "やめとくわ"
 | 
			
		||||
  ok: "これや!"
 | 
			
		||||
desktop/views/components/messaging-room-window.vue:
 | 
			
		||||
  title: "メッセージ:"
 | 
			
		||||
desktop/views/components/messaging-window.vue:
 | 
			
		||||
  title: "メッセージ"
 | 
			
		||||
desktop/views/components/note-detail.vue:
 | 
			
		||||
  private: "この投稿は見せられへんわ"
 | 
			
		||||
  deleted: "この投稿なんか無くなってもうたわ"
 | 
			
		||||
  location: "ここおるで:"
 | 
			
		||||
  renote: "Renote"
 | 
			
		||||
  add-reaction: "リアクション"
 | 
			
		||||
  undo-reaction: "リアクション解除"
 | 
			
		||||
desktop/views/components/note.vue:
 | 
			
		||||
  reply: "返す"
 | 
			
		||||
  renote: "Renote"
 | 
			
		||||
  add-reaction: "リアクション"
 | 
			
		||||
  undo-reaction: "リアクション解除"
 | 
			
		||||
  detail: "もっと"
 | 
			
		||||
  private: "この投稿は見せられへんわ"
 | 
			
		||||
  deleted: "この投稿なんか無くなってもうたわ"
 | 
			
		||||
@@ -859,7 +689,6 @@ desktop/views/components/post-form.vue:
 | 
			
		||||
  attach-media-from-local: "PCからメディア持ってくる"
 | 
			
		||||
  attach-media-from-drive: "ドライブからメディア持ってくる"
 | 
			
		||||
  attach-cancel: "くっつけるのやめよか"
 | 
			
		||||
  insert-a-kao: "v('ω')v"
 | 
			
		||||
  create-poll: "アンケートを作成"
 | 
			
		||||
  text-remain: "残り{}文字"
 | 
			
		||||
  recent-tags: "最近のタグ"
 | 
			
		||||
@@ -910,8 +739,8 @@ desktop/views/components/settings.2fa.vue:
 | 
			
		||||
  failed: "なんか設定に失敗したで。トークンを間違えとらんか確認してや。"
 | 
			
		||||
  info: "次のサインインからは、パスワードに加えてデバイスに出とるトークンを入力してな。"
 | 
			
		||||
common/views/components/media-image.vue:
 | 
			
		||||
  sensitive: "閲覧注意"
 | 
			
		||||
  click-to-show: "クリックして表示"
 | 
			
		||||
  sensitive: "ちょっと見せられへんわ"
 | 
			
		||||
  click-to-show: "クリックして見せるで"
 | 
			
		||||
common/views/components/api-settings.vue:
 | 
			
		||||
  intro: "API使うんやったらこのトークンを「i」っちゅうパラメータにくっつけてリクエストできるで。"
 | 
			
		||||
  caution: "アカウント勝手にいじられるかも知れんから、このトークンは教えたらあかんし、アプリにも書いたらあかんで(これはフリちゃうで)"
 | 
			
		||||
@@ -950,16 +779,13 @@ common/views/components/password-settings.vue:
 | 
			
		||||
  enter-new-password-again: "もっぺん入れてや"
 | 
			
		||||
  not-match: "パスワードがおうとらん"
 | 
			
		||||
  changed: "パスワード変えたわ"
 | 
			
		||||
  failed: "パスワード変更に失敗しました"
 | 
			
		||||
desktop/views/components/sub-note-content.vue:
 | 
			
		||||
  private: "この投稿は見せられへんわ"
 | 
			
		||||
  deleted: "この投稿なんか無くなってもうたわ"
 | 
			
		||||
  media-count: "{}つのメディア"
 | 
			
		||||
  poll: "アンケート"
 | 
			
		||||
desktop/views/components/settings.tags.vue:
 | 
			
		||||
  title: "タグ"
 | 
			
		||||
  query: "クエリ (省略可)"
 | 
			
		||||
  add: "追加"
 | 
			
		||||
  add: "増やす"
 | 
			
		||||
  save: "保存"
 | 
			
		||||
desktop/views/components/taskmanager.vue:
 | 
			
		||||
  title: "タスクマネージャ"
 | 
			
		||||
@@ -969,7 +795,7 @@ desktop/views/components/timeline.vue:
 | 
			
		||||
  hybrid: "ソーシャル"
 | 
			
		||||
  global: "グローバル"
 | 
			
		||||
  mentions: "あんた宛て"
 | 
			
		||||
  messages: "メッセージ"
 | 
			
		||||
  messages: "ダイレクト投稿"
 | 
			
		||||
  list: "リスト"
 | 
			
		||||
  hashtag: "ハッシュタグ"
 | 
			
		||||
  add-tag-timeline: "ハッシュタグ増やす"
 | 
			
		||||
@@ -1021,9 +847,6 @@ admin/views/index.vue:
 | 
			
		||||
  federation: "連合"
 | 
			
		||||
  announcements: "知っといてや"
 | 
			
		||||
  hashtags: "ハッシュタグ"
 | 
			
		||||
  abuse: "スパム報告"
 | 
			
		||||
  queue: "ジョブキュー"
 | 
			
		||||
  logs: "ログ"
 | 
			
		||||
  back-to-misskey: "Misskeyに戻る"
 | 
			
		||||
admin/views/dashboard.vue:
 | 
			
		||||
  dashboard: "ダッシュボード"
 | 
			
		||||
@@ -1033,14 +856,8 @@ admin/views/dashboard.vue:
 | 
			
		||||
  instances: "インスタンス"
 | 
			
		||||
  this-instance: "ワイのインスタンス"
 | 
			
		||||
  federated: "連合"
 | 
			
		||||
admin/views/queue.vue:
 | 
			
		||||
  operation: "操作"
 | 
			
		||||
  remove-all-jobs: "すべてのジョブをクリア"
 | 
			
		||||
admin/views/abuse.vue:
 | 
			
		||||
  title: "スパム報告"
 | 
			
		||||
  target: "対象"
 | 
			
		||||
  reporter: "報告者"
 | 
			
		||||
  details: "詳細"
 | 
			
		||||
  details: "もっと"
 | 
			
		||||
  remove-report: "削除"
 | 
			
		||||
admin/views/instance.vue:
 | 
			
		||||
  instance: "インスタンス"
 | 
			
		||||
@@ -1048,7 +865,6 @@ admin/views/instance.vue:
 | 
			
		||||
  instance-description: "インスタンスの紹介"
 | 
			
		||||
  host: "ホスト"
 | 
			
		||||
  banner-url: "バナー画像URL"
 | 
			
		||||
  error-image-url: "エラー画像URL"
 | 
			
		||||
  languages: "インスタンスの対象言語"
 | 
			
		||||
  languages-desc: "スペースで区切って複数設定できるで。"
 | 
			
		||||
  maintainer-config: "管理者情報"
 | 
			
		||||
@@ -1088,8 +904,6 @@ admin/views/instance.vue:
 | 
			
		||||
  max-note-text-length: "投稿の最大文字数"
 | 
			
		||||
  disable-registration: "ユーザー登録の受付を止める"
 | 
			
		||||
  disable-local-timeline: "ローカルタイムラインを使えんようにする"
 | 
			
		||||
  disable-global-timeline: "グローバルタイムラインを無効にする"
 | 
			
		||||
  disabling-timelines-info: "これらのタイムラインを無効にしても、管理者およびモデレーターは引き続き利用できます。"
 | 
			
		||||
  invite: "来てや"
 | 
			
		||||
  save: "保存"
 | 
			
		||||
  saved: "保存したで!"
 | 
			
		||||
@@ -1107,15 +921,8 @@ admin/views/instance.vue:
 | 
			
		||||
  smtp-secure-info: "STARTTLS使用時はオフにします。"
 | 
			
		||||
  smtp-host: "SMTPホスト"
 | 
			
		||||
  smtp-port: "SMTPポート"
 | 
			
		||||
  smtp-auth: "SMTP認証を行う"
 | 
			
		||||
  smtp-user: "SMTPユーザー"
 | 
			
		||||
  smtp-pass: "SMTPパスワード"
 | 
			
		||||
  serviceworker-config: "ServiceWorker"
 | 
			
		||||
  enable-serviceworker: "ServiceWorkerを有効にする"
 | 
			
		||||
  serviceworker-info: "プッシュ通知を行うには有効する必要があります。"
 | 
			
		||||
  vapid-publickey: "VAPID公開鍵"
 | 
			
		||||
  vapid-privatekey: "VAPID秘密鍵"
 | 
			
		||||
  vapid-info: "ServiceWorkerを有効にする場合、VAPIDキーペアを生成する必要があります。シェルで次のようにします:"
 | 
			
		||||
admin/views/charts.vue:
 | 
			
		||||
  title: "チャート"
 | 
			
		||||
  per-day: "1日ごと"
 | 
			
		||||
@@ -1134,7 +941,6 @@ admin/views/charts.vue:
 | 
			
		||||
    notes-total: "投稿の積算"
 | 
			
		||||
    users: "ユーザーの増減"
 | 
			
		||||
    users-total: "ユーザーの積算"
 | 
			
		||||
    active-users: "アクティブユーザー数"
 | 
			
		||||
    drive: "ドライブ使用量の増減"
 | 
			
		||||
    drive-total: "ドライブ使用量の積算"
 | 
			
		||||
    drive-files: "ドライブのファイル数の増減"
 | 
			
		||||
@@ -1144,168 +950,61 @@ admin/views/charts.vue:
 | 
			
		||||
    network-usage: "通信量"
 | 
			
		||||
admin/views/drive.vue:
 | 
			
		||||
  operation: "操作"
 | 
			
		||||
  fileid-or-url: "ファイルIDまたはファイルURL"
 | 
			
		||||
  file-not-found: "ファイルが見つかりません"
 | 
			
		||||
  lookup: "照会"
 | 
			
		||||
  sort:
 | 
			
		||||
    title: "ソート"
 | 
			
		||||
    createdAtAsc: "アップロード日時が古い順"
 | 
			
		||||
    createdAtDesc: "アップロード日時が新しい順"
 | 
			
		||||
    sizeAsc: "サイズが小さい順"
 | 
			
		||||
    sizeDesc: "サイズが大きい順"
 | 
			
		||||
  origin:
 | 
			
		||||
    title: "オリジン"
 | 
			
		||||
    combined: "ローカル+リモート"
 | 
			
		||||
    local: "ローカル"
 | 
			
		||||
    remote: "リモート"
 | 
			
		||||
  delete: "削除"
 | 
			
		||||
  deleted: "削除しました"
 | 
			
		||||
  mark-as-sensitive: "閲覧注意に設定"
 | 
			
		||||
  unmark-as-sensitive: "閲覧注意を解除"
 | 
			
		||||
  marked-as-sensitive: "閲覧注意に設定しました"
 | 
			
		||||
  unmarked-as-sensitive: "閲覧注意を解除しました"
 | 
			
		||||
  mark-as-sensitive: "見たらあかん感じにしとく"
 | 
			
		||||
  unmark-as-sensitive: "やっぱ見せたるわ"
 | 
			
		||||
admin/views/users.vue:
 | 
			
		||||
  operation: "操作"
 | 
			
		||||
  username-or-userid: "ユーザー名またはユーザーID"
 | 
			
		||||
  user-not-found: "ユーザーが見つからへん!"
 | 
			
		||||
  lookup: "照会"
 | 
			
		||||
  reset-password: "パスワードをリセット"
 | 
			
		||||
  reset-password-confirm: "パスワードをリセットしますか?"
 | 
			
		||||
  password-updated: "パスワードは現在「{password} 」やで"
 | 
			
		||||
  suspend: "凍結"
 | 
			
		||||
  suspend-confirm: "凍結しますか?"
 | 
			
		||||
  suspended: "凍結しました"
 | 
			
		||||
  unsuspend: "凍結の解除"
 | 
			
		||||
  unsuspend-confirm: "凍結を解除しますか?"
 | 
			
		||||
  unsuspended: "凍結を解除しました"
 | 
			
		||||
  make-silence: "サイレンス"
 | 
			
		||||
  unmake-silence: "サイレンスの解除"
 | 
			
		||||
  verify: "公式アカウントにする"
 | 
			
		||||
  verify-confirm: "公式アカウントにしますか?"
 | 
			
		||||
  verified: "公式アカウントにしました"
 | 
			
		||||
  unverify: "公式アカウントを解除する"
 | 
			
		||||
  unverify-confirm: "公式アカウントを解除しますか?"
 | 
			
		||||
  unverified: "公式アカウントを解除しました"
 | 
			
		||||
  update-remote-user: "リモートユーザー情報の更新"
 | 
			
		||||
  remote-user-updated: "リモートユーザー情報を更新しました"
 | 
			
		||||
  users:
 | 
			
		||||
    title: "ユーザー"
 | 
			
		||||
    sort:
 | 
			
		||||
      title: "ソート"
 | 
			
		||||
      createdAtAsc: "登録日時が古い順"
 | 
			
		||||
      createdAtDesc: "登録日時が新しい順"
 | 
			
		||||
      updatedAtAsc: "更新日時が古い順"
 | 
			
		||||
      updatedAtDesc: "更新日時が新しい順"
 | 
			
		||||
    state:
 | 
			
		||||
      title: "状態"
 | 
			
		||||
      all: "すべて"
 | 
			
		||||
      admin: "管理者"
 | 
			
		||||
      moderator: "モデレーター"
 | 
			
		||||
      adminOrModerator: "管理者+モデレーター"
 | 
			
		||||
      verified: "公式アカウント"
 | 
			
		||||
      silenced: "サイレンス済み"
 | 
			
		||||
      suspended: "凍結済み"
 | 
			
		||||
      verified: "アメちゃん付きアカウント"
 | 
			
		||||
    origin:
 | 
			
		||||
      title: "オリジン"
 | 
			
		||||
      combined: "ローカル+リモート"
 | 
			
		||||
      local: "ローカル"
 | 
			
		||||
      remote: "リモート"
 | 
			
		||||
    createdAt: "登録日時"
 | 
			
		||||
    updatedAt: "更新日時"
 | 
			
		||||
admin/views/moderators.vue:
 | 
			
		||||
  add-moderator:
 | 
			
		||||
    title: "モデレーターの登録"
 | 
			
		||||
    add: "登録"
 | 
			
		||||
    added: "モデレーターを登録しました"
 | 
			
		||||
    remove: "解除"
 | 
			
		||||
    removed: "モデレーター登録を解除しました"
 | 
			
		||||
admin/views/emoji.vue:
 | 
			
		||||
  add-emoji:
 | 
			
		||||
    title: "絵文字の登録"
 | 
			
		||||
    name: "絵文字名"
 | 
			
		||||
    name-desc: "a~z 0~9 _ の文字が使えます。"
 | 
			
		||||
    aliases: "エイリアス"
 | 
			
		||||
    aliases-desc: "スペースで区切って複数設定できます。"
 | 
			
		||||
    url: "絵文字画像URL"
 | 
			
		||||
    add: "追加"
 | 
			
		||||
    info: "50KB以下のPNG画像をおすすめします。"
 | 
			
		||||
    added: "絵文字を登録しました"
 | 
			
		||||
    add: "増やす"
 | 
			
		||||
  emojis:
 | 
			
		||||
    title: "絵文字一覧"
 | 
			
		||||
    update: "更新"
 | 
			
		||||
    remove: "削除"
 | 
			
		||||
  updated: "更新しました"
 | 
			
		||||
  remove-emoji:
 | 
			
		||||
    are-you-sure: "「$1」を削除しますか?"
 | 
			
		||||
    removed: "削除しました"
 | 
			
		||||
admin/views/announcements.vue:
 | 
			
		||||
  announcements: "お知らせ"
 | 
			
		||||
  announcements: "知っときや"
 | 
			
		||||
  save: "保存"
 | 
			
		||||
  remove: "削除"
 | 
			
		||||
  add: "追加"
 | 
			
		||||
  title: "タイトル"
 | 
			
		||||
  text: "内容"
 | 
			
		||||
  saved: "保存しました"
 | 
			
		||||
  _remove:
 | 
			
		||||
    are-you-sure: "「$1」を削除しますか?"
 | 
			
		||||
    removed: "削除しました"
 | 
			
		||||
admin/views/hashtags.vue:
 | 
			
		||||
  hided-tags: "Hidden Tags"
 | 
			
		||||
  add: "増やす"
 | 
			
		||||
  saved: "保存したで!"
 | 
			
		||||
admin/views/federation.vue:
 | 
			
		||||
  federation: "連合"
 | 
			
		||||
  instance: "インスタンス"
 | 
			
		||||
  host: "ホスト"
 | 
			
		||||
  notes: "投稿"
 | 
			
		||||
  users: "ユーザー"
 | 
			
		||||
  following: "フォロー中"
 | 
			
		||||
  following: "フォローしとる"
 | 
			
		||||
  followers: "フォロワー"
 | 
			
		||||
  status: "ステータス"
 | 
			
		||||
  latest-request-sent-at: "直近のリクエスト送信"
 | 
			
		||||
  latest-request-received-at: "直近のリクエスト受信"
 | 
			
		||||
  remove-all-following: "フォローを全解除"
 | 
			
		||||
  remove-all-following-info: "{host}からのフォローをすべて解除します。そのインスタンスがもう存在しなくなった場合などに実行してください。"
 | 
			
		||||
  block: "ブロック"
 | 
			
		||||
  marked-as-closed: "閉鎖されているとマーク"
 | 
			
		||||
  lookup: "照会"
 | 
			
		||||
  instances: "インスタンス"
 | 
			
		||||
  instance-not-registered: "そのインスタンスは登録されていません"
 | 
			
		||||
  sort: "ソート"
 | 
			
		||||
  sorts:
 | 
			
		||||
    caughtAtAsc: "登録日時が古い順"
 | 
			
		||||
    caughtAtDesc: "登録日時が新しい順"
 | 
			
		||||
    lastCommunicatedAtAsc: "最後にやり取りした日時が古い順"
 | 
			
		||||
    lastCommunicatedAtDesc: "最後にやり取りした日時が新しい順"
 | 
			
		||||
    notesAsc: "投稿が少ない順"
 | 
			
		||||
    notesDesc: "投稿が多い順"
 | 
			
		||||
    usersAsc: "ユーザーが少ない順"
 | 
			
		||||
    usersDesc: "ユーザーが多い順"
 | 
			
		||||
    followingAsc: "フォローが少ない順"
 | 
			
		||||
    followingDesc: "フォローが多い順"
 | 
			
		||||
    followersAsc: "フォロワーが少ない順"
 | 
			
		||||
    followersDesc: "フォロワーが多い順"
 | 
			
		||||
    driveUsageAsc: "ドライブ使用量が少ない順"
 | 
			
		||||
    driveUsageDesc: "ドライブ使用量が多い順"
 | 
			
		||||
    driveFilesAsc: "ドライブのファイル数が少ない順"
 | 
			
		||||
    driveFilesDesc: "ドライブのファイル数が多い順"
 | 
			
		||||
  state: "状態"
 | 
			
		||||
  instances: "連合"
 | 
			
		||||
  states:
 | 
			
		||||
    all: "すべて"
 | 
			
		||||
    blocked: "ブロック"
 | 
			
		||||
    not-responding: "応答なし"
 | 
			
		||||
    marked-as-closed: "閉鎖とマーク済み"
 | 
			
		||||
  result-is-truncated: "上位{n}件を表示しています。"
 | 
			
		||||
  charts: "チャート"
 | 
			
		||||
  chart-srcs:
 | 
			
		||||
    requests: "リクエスト"
 | 
			
		||||
    users: "ユーザーの増減"
 | 
			
		||||
    users-total: "ユーザーの積算"
 | 
			
		||||
    notes: "投稿の増減"
 | 
			
		||||
    notes-total: "投稿の積算"
 | 
			
		||||
    ff: "フォロー/フォロワーの増減"
 | 
			
		||||
    ff-total: "フォロー/フォロワーの積算"
 | 
			
		||||
    drive-usage: "ドライブ使用量の増減"
 | 
			
		||||
    drive-usage-total: "ドライブ使用量の積算"
 | 
			
		||||
    drive-files: "ドライブファイル数の増減"
 | 
			
		||||
    drive-files-total: "ドライブファイル数の積算"
 | 
			
		||||
  chart-spans:
 | 
			
		||||
    hour: "1時間ごと"
 | 
			
		||||
    day: "1日ごと"
 | 
			
		||||
@@ -1328,11 +1027,6 @@ desktop/views/pages/selectdrive.vue:
 | 
			
		||||
  upload: "PCからドライブにファイル上げる"
 | 
			
		||||
desktop/views/pages/search.vue:
 | 
			
		||||
  not-available: "検索機能は使えへんわ。管理者がそう言うとる。"
 | 
			
		||||
  not-found: "「{q}」に関する投稿は見つかりませんでした。"
 | 
			
		||||
desktop/views/pages/share.vue:
 | 
			
		||||
  share-with: "{name}で共有"
 | 
			
		||||
desktop/views/pages/tag.vue:
 | 
			
		||||
  no-posts-found: "ハッシュタグ「{q}」が付けられた投稿は見つかりませんでした。"
 | 
			
		||||
desktop/views/pages/user-list.users.vue:
 | 
			
		||||
  users: "ユーザー"
 | 
			
		||||
  add-user: "ユーザー増やす"
 | 
			
		||||
@@ -1354,19 +1048,15 @@ desktop/views/pages/user/user.header.vue:
 | 
			
		||||
  following: "フォロー"
 | 
			
		||||
  followers: "フォロワー"
 | 
			
		||||
  is-bot: "このアカウントはBotや"
 | 
			
		||||
  no-description: "自己紹介はありません"
 | 
			
		||||
  years-old: "{age}歳"
 | 
			
		||||
  year: "年"
 | 
			
		||||
  month: "月"
 | 
			
		||||
  day: "日"
 | 
			
		||||
  follows-you: "フォローされています"
 | 
			
		||||
  follows-you: "フォローされとるで"
 | 
			
		||||
desktop/views/pages/user/user.timeline.vue:
 | 
			
		||||
  default: "投稿"
 | 
			
		||||
  with-replies: "投稿と返信"
 | 
			
		||||
  with-media: "メディア"
 | 
			
		||||
  my-posts: "私の投稿"
 | 
			
		||||
desktop/views/widgets/messaging.vue:
 | 
			
		||||
  title: "メッセージ"
 | 
			
		||||
desktop/views/widgets/notifications.vue:
 | 
			
		||||
  title: "通知"
 | 
			
		||||
desktop/views/widgets/polls.vue:
 | 
			
		||||
@@ -1397,7 +1087,6 @@ mobile/views/components/drive.vue:
 | 
			
		||||
  prompt: "何すんの?(数字を入れてや): <1 → ファイルをアップロード | 2 → ファイルをURLでアップロード | 3 → フォルダ作成 | 4 → このフォルダ名を変更 | 5 → このフォルダを移動 | 6 → このフォルダを削除>"
 | 
			
		||||
  deletion-alert: "フォルダの削除は未実装やねん...。堪忍な!"
 | 
			
		||||
  folder-name: "フォルダー名"
 | 
			
		||||
  here-is-root: "現在いる場所はルートで、フォルダではありません。"
 | 
			
		||||
  url-prompt: "このURLのファイルをアップロードしたいねん"
 | 
			
		||||
  uploading: "アップロードをリクエストしたで。アップロードが完了するまで時間がかかるかも分からん、知らんけど。"
 | 
			
		||||
mobile/views/components/drive-file-chooser.vue:
 | 
			
		||||
@@ -1488,13 +1177,12 @@ mobile/views/pages/home.vue:
 | 
			
		||||
  hybrid: "ソーシャル"
 | 
			
		||||
  global: "グローバル"
 | 
			
		||||
  mentions: "あんた宛て"
 | 
			
		||||
  messages: "メッセージ"
 | 
			
		||||
  messages: "ダイレクト投稿"
 | 
			
		||||
mobile/views/pages/tag.vue:
 | 
			
		||||
  no-posts-found: "ハッシュタグ「{q}」が付けられた投稿はあらへんかった。"
 | 
			
		||||
mobile/views/pages/widgets.vue:
 | 
			
		||||
  dashboard: "ダッシュボード"
 | 
			
		||||
  widgets-hints: "ウィジェットを追加/削除したり並べ替えたりできます。ウィジェットを移動するには「三」をドラッグします。ウィジェットを削除するには「x」をタップします。いくつかのウィジェットはタップすることで表示を変更できます。"
 | 
			
		||||
  add-widget: "追加"
 | 
			
		||||
  add-widget: "増やす"
 | 
			
		||||
  customization-tips: "カスタマイズのヒント"
 | 
			
		||||
mobile/views/pages/widgets/activity.vue:
 | 
			
		||||
  activity: "やっとること"
 | 
			
		||||
@@ -1532,7 +1220,7 @@ mobile/views/pages/user/home.vue:
 | 
			
		||||
  activity: "やっとること"
 | 
			
		||||
  keywords: "キーワード"
 | 
			
		||||
  domains: "よく出るドメイン"
 | 
			
		||||
  frequently-replied-users: "よく話すユーザー"
 | 
			
		||||
  frequently-replied-users: "よう話すツレ"
 | 
			
		||||
  followers-you-know: "知っとるフォロワー"
 | 
			
		||||
  last-used-at: "最後いつ来た?"
 | 
			
		||||
mobile/views/pages/user/home.photos.vue:
 | 
			
		||||
@@ -1548,7 +1236,6 @@ deck:
 | 
			
		||||
  direct: "ダイレクト投稿"
 | 
			
		||||
  notifications: "通知"
 | 
			
		||||
  list: "リスト"
 | 
			
		||||
  select-list: "リストを選択してください"
 | 
			
		||||
  swap-left: "左に移動や!"
 | 
			
		||||
  swap-right: "右に移動や!"
 | 
			
		||||
  swap-up: "上に移動や!"
 | 
			
		||||
@@ -1558,14 +1245,11 @@ deck:
 | 
			
		||||
  rename: "名前を変えるで"
 | 
			
		||||
  stack-left: "左に重ねんで!"
 | 
			
		||||
  pop-right: "右に出すで!"
 | 
			
		||||
  disabled-timeline:
 | 
			
		||||
    title: "無効化されたタイムライン"
 | 
			
		||||
    description: "サーバーの運営者により、このタイムラインは使用できない状態に設定されています。"
 | 
			
		||||
deck/deck.tl-column.vue:
 | 
			
		||||
  is-media-only: "メディア投稿だけや"
 | 
			
		||||
  edit: "オプション"
 | 
			
		||||
deck/deck.user-column.vue:
 | 
			
		||||
  follows-you: "フォローされています"
 | 
			
		||||
  follows-you: "フォローされとるで"
 | 
			
		||||
  posts: "投稿"
 | 
			
		||||
  following: "フォロー"
 | 
			
		||||
  followers: "フォロワー"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,13 @@
 | 
			
		||||
---
 | 
			
		||||
meta:
 | 
			
		||||
  lang: "한국어"
 | 
			
		||||
  divider: ""
 | 
			
		||||
common:
 | 
			
		||||
  misskey: "연합우주의 ⭐"
 | 
			
		||||
  about-title: "연합우주의 ⭐."
 | 
			
		||||
  about: "Misskey를 찾아주셔서 감사합니다. Misskey는 지구에서 태어난 <b>분산 마이크로 블로그 SNS </b> 입니다. Fediverse(다양한 SNS로 구성되는 우주)에 존재하는 다른 SNS와 상호 연결되어 있습니다. 잠시 도시의 번잡함에서 벗어나 새로운 인터넷에 다이브 해 보지 않겠습니까."
 | 
			
		||||
  intro:
 | 
			
		||||
    title: "Misskey란?"
 | 
			
		||||
    about: "Misskey는 오픈소스 <b>분산형 마이크로블로그 SNS</b>입니다. 다양하고 폭넓게 커스터마이징할 수 있는 UI, 글에 대한 반응, 파일을 관리할 수 있는 드라이브 등의 선진적인 기능을 갖추고 있습니다. 더하여 Fediverse라고 부르는 네트워크에 연결할 수 있어 다른 SNS와도 주고받을 수 있습니다. 예를 들자면, 당신이 무언가를 게시하면, 해당 게시물은 Misskey 뿐만 아니라 다른 SNS에도 전해집니다. 살짝 어떤 행성에서 다른 행성으로 전파를 발신하고 있는 모습을 상상해주세요."
 | 
			
		||||
    about: "Misskey는 오픈소스 <b>분산형 마이크로블로그 SNS</b>입니다. 다양하고 폭넓게 커스터마이징할 수 있는 UI, 글에 대한 리액션, 파일을 관리할 수 있는 드라이브 등의 선진적인 기능을 갖추고 있습니다. 더하여 Fediverse라고 부르는 네트워크에 연결할 수 있어 다른 SNS와도 주고받을 수 있습니다. 예를 들자면, 당신이 무언가를 게시하면, 해당 게시물은 Misskey 뿐만 아니라 다른 SNS에도 전해집니다. 살짝 어떤 행성에서 다른 행성으로 전파를 발신하고 있는 모습을 상상해주세요."
 | 
			
		||||
    features: "특징"
 | 
			
		||||
    rich-contents: "글"
 | 
			
		||||
    rich-contents-desc: "자신의 생각, 화제의 사건, 모두와 공유하고 싶은 것을 올려주세요. 필요한 경우 다양한 스타일을 사용하여 글을 장식하거나 마음에 드는 이미지, 영상 등의 파일이나 투표를 올리는 것도 가능합니다."
 | 
			
		||||
@@ -315,6 +314,7 @@ common/views/pages/explore.vue:
 | 
			
		||||
  users-info: "현재 {users} 사용자가 등록되어 있습니다"
 | 
			
		||||
common/views/components/url-preview.vue:
 | 
			
		||||
  enable-player: "플레이어 열기"
 | 
			
		||||
  disable-player: "플레이어 닫기"
 | 
			
		||||
common/views/components/user-list.vue:
 | 
			
		||||
  no-users: "사용자가 없습니다"
 | 
			
		||||
common/views/components/games/reversi/reversi.vue:
 | 
			
		||||
@@ -490,18 +490,37 @@ common/views/components/user-menu.vue:
 | 
			
		||||
common/views/components/poll.vue:
 | 
			
		||||
  vote-to: "\"{}\"에 투표하기"
 | 
			
		||||
  vote-count: "{}표"
 | 
			
		||||
  total-users: "{}명이 투표"
 | 
			
		||||
  total-votes: "총 {}표"
 | 
			
		||||
  vote: "투표하기"
 | 
			
		||||
  show-result: "결과 보기"
 | 
			
		||||
  voted: "투표함"
 | 
			
		||||
  closed: "종료됨"
 | 
			
		||||
  remaining-days: "종료까지 앞으로 {d}일 {h}시간"
 | 
			
		||||
  remaining-hours: "종료까지 앞으로 {h}시간 {m}분"
 | 
			
		||||
  remaining-minutes: "종료까지 앞으로 {m}분 {s}초"
 | 
			
		||||
  remaining-seconds: "종료까지 앞으로 {s}초"
 | 
			
		||||
common/views/components/poll-editor.vue:
 | 
			
		||||
  no-only-one-choice: "투표에는 선택지가 최소한 두 개 필요합니다"
 | 
			
		||||
  choice-n: "선택지 {}"
 | 
			
		||||
  remove: "이 선택지를 제거"
 | 
			
		||||
  add: "+선택지 추가"
 | 
			
		||||
  destroy: "투표 제거"
 | 
			
		||||
  multiple: "복수 응답 가능"
 | 
			
		||||
  expiration: "기한"
 | 
			
		||||
  infinite: "무기한"
 | 
			
		||||
  at: "일시 지정"
 | 
			
		||||
  after: "기간 지정"
 | 
			
		||||
  no-more: "더 이상 추가할 수 없습니다"
 | 
			
		||||
  deadline-date: "기한"
 | 
			
		||||
  deadline-time: "시간"
 | 
			
		||||
  interval: "기간"
 | 
			
		||||
  unit: "단위"
 | 
			
		||||
  second: "초"
 | 
			
		||||
  minute: "분"
 | 
			
		||||
  hour: "시간"
 | 
			
		||||
  day: "일"
 | 
			
		||||
common/views/components/reaction-picker.vue:
 | 
			
		||||
  choose-reaction: "반응 선택"
 | 
			
		||||
  choose-reaction: "리액션 선택"
 | 
			
		||||
common/views/components/emoji-picker.vue:
 | 
			
		||||
  custom-emoji: "커스텀 이모지"
 | 
			
		||||
  people: "사람들"
 | 
			
		||||
@@ -629,12 +648,16 @@ common/views/components/profile-editor.vue:
 | 
			
		||||
  email-verified: "매일 주소가 확인되었습니다"
 | 
			
		||||
  email-not-verified: "메일 주소가 확인되지 않았습니다. 받은 편지함을 확인하여 주시기 바랍니다."
 | 
			
		||||
  export: "내보내기"
 | 
			
		||||
  import: "가져오기"
 | 
			
		||||
  export-and-import: "내보내기와 가져오기"
 | 
			
		||||
  export-targets:
 | 
			
		||||
    all-notes: "모든 글 데이터"
 | 
			
		||||
    following-list: "팔로잉"
 | 
			
		||||
    mute-list: "뮤트"
 | 
			
		||||
    blocking-list: "차단"
 | 
			
		||||
    user-lists: "리스트"
 | 
			
		||||
  export-requested: "내보내기를 요청하였습니다. 이 작업은 시간이 걸릴 수 있습니다. 내보내기가 완료되면 드라이브에 파일이 추가됩니다."
 | 
			
		||||
  import-requested: "가져오기를 요청하였습니다. 이 작업에는 시간이 걸릴 수 있습니다."
 | 
			
		||||
  enter-password: "비밀번호를 입력하여 주십시오"
 | 
			
		||||
  danger-zone: "위험한 설정"
 | 
			
		||||
  delete-account: "계정 삭제"
 | 
			
		||||
@@ -816,10 +839,6 @@ desktop/views/components/home.vue:
 | 
			
		||||
desktop/views/input-dialog.vue:
 | 
			
		||||
  cancel: "취소"
 | 
			
		||||
  ok: "확인"
 | 
			
		||||
desktop/views/components/messaging-room-window.vue:
 | 
			
		||||
  title: "메시지:"
 | 
			
		||||
desktop/views/components/messaging-window.vue:
 | 
			
		||||
  title: "메시지"
 | 
			
		||||
desktop/views/components/note-detail.vue:
 | 
			
		||||
  private: "이 글은 비공개입니다"
 | 
			
		||||
  deleted: "이 글은 삭제되었습니다"
 | 
			
		||||
@@ -969,7 +988,7 @@ desktop/views/components/timeline.vue:
 | 
			
		||||
  hybrid: "소셜"
 | 
			
		||||
  global: "글로벌"
 | 
			
		||||
  mentions: "받은 멘션"
 | 
			
		||||
  messages: "메시지"
 | 
			
		||||
  messages: "다이렉트 게시글"
 | 
			
		||||
  list: "리스트"
 | 
			
		||||
  hashtag: "해시태그"
 | 
			
		||||
  add-tag-timeline: "해시태그 추가"
 | 
			
		||||
@@ -1034,7 +1053,7 @@ admin/views/dashboard.vue:
 | 
			
		||||
  this-instance: "이 인스턴스"
 | 
			
		||||
  federated: "연합"
 | 
			
		||||
admin/views/queue.vue:
 | 
			
		||||
  operation: "동작"
 | 
			
		||||
  title: "큐"
 | 
			
		||||
  remove-all-jobs: "모든 작업 제거"
 | 
			
		||||
admin/views/abuse.vue:
 | 
			
		||||
  title: "스팸 신고"
 | 
			
		||||
@@ -1090,6 +1109,8 @@ admin/views/instance.vue:
 | 
			
		||||
  disable-local-timeline: "로컬 타임라인 비활성화"
 | 
			
		||||
  disable-global-timeline: "글로벌 타임라인 비활성화"
 | 
			
		||||
  disabling-timelines-info: "이 타임라인들을 비활성화해도 관리자 및 모더레이터는 계속 사용할 수 있습니다."
 | 
			
		||||
  enable-emoji-reaction: "리액션에 이모지를 사용할 수 있게 함"
 | 
			
		||||
  use-star-for-reaction-fallback: "알 수 없는 리액션을 star로 대체하여 사용"
 | 
			
		||||
  invite: "초대"
 | 
			
		||||
  save: "저장"
 | 
			
		||||
  saved: "저장하였습니다"
 | 
			
		||||
@@ -1252,12 +1273,13 @@ admin/views/announcements.vue:
 | 
			
		||||
admin/views/hashtags.vue:
 | 
			
		||||
  hided-tags: "Hidden Tags"
 | 
			
		||||
admin/views/federation.vue:
 | 
			
		||||
  federation: "연합"
 | 
			
		||||
  instance: "인스턴스"
 | 
			
		||||
  host: "호스트"
 | 
			
		||||
  notes: "글"
 | 
			
		||||
  users: "사용자"
 | 
			
		||||
  following: "팔로우 중"
 | 
			
		||||
  followers: "팔로워"
 | 
			
		||||
  caught-at: "등록 날짜"
 | 
			
		||||
  status: "상태"
 | 
			
		||||
  latest-request-sent-at: "마지막으로 요청을 전송한 시간"
 | 
			
		||||
  latest-request-received-at: "마지막으로 요청을 받은 시간"
 | 
			
		||||
@@ -1266,7 +1288,7 @@ admin/views/federation.vue:
 | 
			
		||||
  block: "차단"
 | 
			
		||||
  marked-as-closed: "폐쇄된 것으로 표시"
 | 
			
		||||
  lookup: "조회"
 | 
			
		||||
  instances: "인스턴스"
 | 
			
		||||
  instances: "연합"
 | 
			
		||||
  instance-not-registered: "해당 인스턴스가 등록되어 있지 않습니다"
 | 
			
		||||
  sort: "정렬"
 | 
			
		||||
  sorts:
 | 
			
		||||
@@ -1329,8 +1351,6 @@ desktop/views/pages/selectdrive.vue:
 | 
			
		||||
desktop/views/pages/search.vue:
 | 
			
		||||
  not-available: "검색 기능은 인스턴스 설정에서 비활성화되어 있습니다."
 | 
			
		||||
  not-found: "\"{q}\" 와 일치하는 글을 찾을 수 없습니다."
 | 
			
		||||
desktop/views/pages/share.vue:
 | 
			
		||||
  share-with: "{name}(으)로 공유"
 | 
			
		||||
desktop/views/pages/tag.vue:
 | 
			
		||||
  no-posts-found: "해시태그 \"{q}\"가 붙은 글을 찾을 수 없습니다."
 | 
			
		||||
desktop/views/pages/user-list.users.vue:
 | 
			
		||||
@@ -1365,8 +1385,6 @@ desktop/views/pages/user/user.timeline.vue:
 | 
			
		||||
  with-replies: "글과 답글"
 | 
			
		||||
  with-media: "미디어"
 | 
			
		||||
  my-posts: "내 글"
 | 
			
		||||
desktop/views/widgets/messaging.vue:
 | 
			
		||||
  title: "메시지"
 | 
			
		||||
desktop/views/widgets/notifications.vue:
 | 
			
		||||
  title: "알림"
 | 
			
		||||
desktop/views/widgets/polls.vue:
 | 
			
		||||
@@ -1488,7 +1506,7 @@ mobile/views/pages/home.vue:
 | 
			
		||||
  hybrid: "소셜"
 | 
			
		||||
  global: "글로벌"
 | 
			
		||||
  mentions: "받은 멘션"
 | 
			
		||||
  messages: "메시지"
 | 
			
		||||
  messages: "다이렉트 게시글"
 | 
			
		||||
mobile/views/pages/tag.vue:
 | 
			
		||||
  no-posts-found: "해시태그 \"{q}\"가 붙은 글을 찾을 수 없습니다."
 | 
			
		||||
mobile/views/pages/widgets.vue:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1238
									
								
								locales/nl-NL.yml
									
									
									
									
									
								
							
							
						
						
									
										1238
									
								
								locales/nl-NL.yml
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1288
									
								
								locales/no-NO.yml
									
									
									
									
									
								
							
							
						
						
									
										1288
									
								
								locales/no-NO.yml
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1465
									
								
								locales/pt-PT.yml
									
									
									
									
									
								
							
							
						
						
									
										1465
									
								
								locales/pt-PT.yml
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1501
									
								
								locales/ru-RU.yml
									
									
									
									
									
								
							
							
						
						
									
										1501
									
								
								locales/ru-RU.yml
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,7 +1,6 @@
 | 
			
		||||
---
 | 
			
		||||
meta:
 | 
			
		||||
  lang: "中文(简体)"
 | 
			
		||||
  divider: ""
 | 
			
		||||
common:
 | 
			
		||||
  misskey: "Fediverse中的一颗⭐"
 | 
			
		||||
  about-title: "Fediverse中的一颗⭐"
 | 
			
		||||
@@ -315,6 +314,7 @@ common/views/pages/explore.vue:
 | 
			
		||||
  users-info: "当前有{users}个注册用户"
 | 
			
		||||
common/views/components/url-preview.vue:
 | 
			
		||||
  enable-player: "打开播放器"
 | 
			
		||||
  disable-player: "关闭播放器"
 | 
			
		||||
common/views/components/user-list.vue:
 | 
			
		||||
  no-users: "无用户"
 | 
			
		||||
common/views/components/games/reversi/reversi.vue:
 | 
			
		||||
@@ -490,16 +490,35 @@ common/views/components/user-menu.vue:
 | 
			
		||||
common/views/components/poll.vue:
 | 
			
		||||
  vote-to: "为\"{}\"投票"
 | 
			
		||||
  vote-count: "{}票"
 | 
			
		||||
  total-users: "{} 人投票"
 | 
			
		||||
  total-votes: "总票数{}"
 | 
			
		||||
  vote: "投票"
 | 
			
		||||
  show-result: "显示结果"
 | 
			
		||||
  voted: "已投票"
 | 
			
		||||
  closed: "已截止"
 | 
			
		||||
  remaining-days: "{d}天{h}小时后截止"
 | 
			
		||||
  remaining-hours: "{h}小时{m}分后截止"
 | 
			
		||||
  remaining-minutes: "{m}分{s}秒后截止"
 | 
			
		||||
  remaining-seconds: "{s}秒后截止"
 | 
			
		||||
common/views/components/poll-editor.vue:
 | 
			
		||||
  no-only-one-choice: "至少选择两个选项"
 | 
			
		||||
  choice-n: "选择{}"
 | 
			
		||||
  remove: "删除选项"
 | 
			
		||||
  add: "+添加一个选项"
 | 
			
		||||
  destroy: "放弃投票"
 | 
			
		||||
  multiple: "允许多个投票"
 | 
			
		||||
  expiration: "截止时间"
 | 
			
		||||
  infinite: "永久"
 | 
			
		||||
  at: "指定日期"
 | 
			
		||||
  after: "指定时间"
 | 
			
		||||
  no-more: "最多只能添加十个回答"
 | 
			
		||||
  deadline-date: "日期"
 | 
			
		||||
  deadline-time: "时间"
 | 
			
		||||
  interval: "时长"
 | 
			
		||||
  unit: "单位"
 | 
			
		||||
  second: "秒"
 | 
			
		||||
  minute: "分"
 | 
			
		||||
  hour: "小时"
 | 
			
		||||
  day: "日"
 | 
			
		||||
common/views/components/reaction-picker.vue:
 | 
			
		||||
  choose-reaction: "选择回应"
 | 
			
		||||
common/views/components/emoji-picker.vue:
 | 
			
		||||
@@ -558,7 +577,7 @@ common/views/components/notification-settings.vue:
 | 
			
		||||
  mark-as-read-all-unread-notes: "将所有帖子标为已读"
 | 
			
		||||
  mark-as-read-all-talk-messages: "将所有对话标为已读"
 | 
			
		||||
  auto-watch: "自动查看帖子"
 | 
			
		||||
  auto-watch-desc: "自动接收有关您做出反应或回复的帖子的通知。"
 | 
			
		||||
  auto-watch-desc: "自动接收有关您做出回应或回复的帖子的通知。"
 | 
			
		||||
common/views/components/integration-settings.vue:
 | 
			
		||||
  title: "服务合作"
 | 
			
		||||
  connect: "连接"
 | 
			
		||||
@@ -629,12 +648,16 @@ common/views/components/profile-editor.vue:
 | 
			
		||||
  email-verified: "电子邮件地址已验证"
 | 
			
		||||
  email-not-verified: "邮件地址尚未验证。 请检查您的邮箱。"
 | 
			
		||||
  export: "导出"
 | 
			
		||||
  import: "导入"
 | 
			
		||||
  export-and-import: "导出/导入"
 | 
			
		||||
  export-targets:
 | 
			
		||||
    all-notes: "所有发帖"
 | 
			
		||||
    following-list: "关注列表"
 | 
			
		||||
    mute-list: "屏蔽列表"
 | 
			
		||||
    blocking-list: "黑名单"
 | 
			
		||||
    user-lists: "列表"
 | 
			
		||||
  export-requested: "导出请求已提交。可能需要花一些时间。导出的文件将保存到网盘中。"
 | 
			
		||||
  import-requested: "导入请求已提交。这可能需要花一点时间。"
 | 
			
		||||
  enter-password: "请输入您的密码"
 | 
			
		||||
  danger-zone: "危险选项"
 | 
			
		||||
  delete-account: "删除帐户"
 | 
			
		||||
@@ -816,22 +839,18 @@ desktop/views/components/home.vue:
 | 
			
		||||
desktop/views/input-dialog.vue:
 | 
			
		||||
  cancel: "取消"
 | 
			
		||||
  ok: "确定"
 | 
			
		||||
desktop/views/components/messaging-room-window.vue:
 | 
			
		||||
  title: "信息:"
 | 
			
		||||
desktop/views/components/messaging-window.vue:
 | 
			
		||||
  title: "正在聊天"
 | 
			
		||||
desktop/views/components/note-detail.vue:
 | 
			
		||||
  private: "私密投稿"
 | 
			
		||||
  deleted: "投稿已删除"
 | 
			
		||||
  location: "位置信息"
 | 
			
		||||
  renote: "转发"
 | 
			
		||||
  add-reaction: "添加一个反应"
 | 
			
		||||
  undo-reaction: "取消反应"
 | 
			
		||||
  add-reaction: "回应"
 | 
			
		||||
  undo-reaction: "取消回应"
 | 
			
		||||
desktop/views/components/note.vue:
 | 
			
		||||
  reply: "回复"
 | 
			
		||||
  renote: "Renote"
 | 
			
		||||
  add-reaction: "添加一个反应"
 | 
			
		||||
  undo-reaction: "取消反应"
 | 
			
		||||
  add-reaction: "回应"
 | 
			
		||||
  undo-reaction: "取消回应"
 | 
			
		||||
  detail: "详细信息"
 | 
			
		||||
  private: "这个投稿是私密的"
 | 
			
		||||
  deleted: "投稿已删除"
 | 
			
		||||
@@ -969,7 +988,7 @@ desktop/views/components/timeline.vue:
 | 
			
		||||
  hybrid: "社交"
 | 
			
		||||
  global: "全球"
 | 
			
		||||
  mentions: "提到的"
 | 
			
		||||
  messages: "信息"
 | 
			
		||||
  messages: "直接发布"
 | 
			
		||||
  list: "列表"
 | 
			
		||||
  hashtag: "标签"
 | 
			
		||||
  add-tag-timeline: "添加标签"
 | 
			
		||||
@@ -1034,7 +1053,7 @@ admin/views/dashboard.vue:
 | 
			
		||||
  this-instance: "此实例"
 | 
			
		||||
  federated: "联合"
 | 
			
		||||
admin/views/queue.vue:
 | 
			
		||||
  operation: "操作"
 | 
			
		||||
  title: "队列"
 | 
			
		||||
  remove-all-jobs: "清除所有作业"
 | 
			
		||||
admin/views/abuse.vue:
 | 
			
		||||
  title: "举报垃圾信息"
 | 
			
		||||
@@ -1090,6 +1109,8 @@ admin/views/instance.vue:
 | 
			
		||||
  disable-local-timeline: "停用本地时间线功能"
 | 
			
		||||
  disable-global-timeline: "禁用全局时间线"
 | 
			
		||||
  disabling-timelines-info: "即使禁用时间线,管理员和版主仍然可用。"
 | 
			
		||||
  enable-emoji-reaction: "在回应上使用表情符号"
 | 
			
		||||
  use-star-for-reaction-fallback: "使用默认的star来表示未知的回应"
 | 
			
		||||
  invite: "邀请"
 | 
			
		||||
  save: "保存"
 | 
			
		||||
  saved: "保存完毕"
 | 
			
		||||
@@ -1252,12 +1273,13 @@ admin/views/announcements.vue:
 | 
			
		||||
admin/views/hashtags.vue:
 | 
			
		||||
  hided-tags: "隐藏标签"
 | 
			
		||||
admin/views/federation.vue:
 | 
			
		||||
  federation: "联合"
 | 
			
		||||
  instance: "例"
 | 
			
		||||
  host: "主机名"
 | 
			
		||||
  notes: "帖子"
 | 
			
		||||
  users: "用户"
 | 
			
		||||
  following: "正在关注"
 | 
			
		||||
  followers: "关注者"
 | 
			
		||||
  caught-at: "注册日期"
 | 
			
		||||
  status: "状态"
 | 
			
		||||
  latest-request-sent-at: "上次发送的请求"
 | 
			
		||||
  latest-request-received-at: "上次收到的请求"
 | 
			
		||||
@@ -1266,7 +1288,7 @@ admin/views/federation.vue:
 | 
			
		||||
  block: "拉黑"
 | 
			
		||||
  marked-as-closed: "标记为已关闭"
 | 
			
		||||
  lookup: "查询"
 | 
			
		||||
  instances: "实例"
 | 
			
		||||
  instances: "联合"
 | 
			
		||||
  instance-not-registered: "实例未注册"
 | 
			
		||||
  sort: "排序"
 | 
			
		||||
  sorts:
 | 
			
		||||
@@ -1329,8 +1351,6 @@ desktop/views/pages/selectdrive.vue:
 | 
			
		||||
desktop/views/pages/search.vue:
 | 
			
		||||
  not-available: "在此实例的设置中关闭搜索功能。"
 | 
			
		||||
  not-found: "没有找到“{q}”的帖子"
 | 
			
		||||
desktop/views/pages/share.vue:
 | 
			
		||||
  share-with: "共享{name}"
 | 
			
		||||
desktop/views/pages/tag.vue:
 | 
			
		||||
  no-posts-found: "没有找到带有主题标签“{q}”的帖子"
 | 
			
		||||
desktop/views/pages/user-list.users.vue:
 | 
			
		||||
@@ -1365,8 +1385,6 @@ desktop/views/pages/user/user.timeline.vue:
 | 
			
		||||
  with-replies: "帖子与回复"
 | 
			
		||||
  with-media: "媒体"
 | 
			
		||||
  my-posts: "我的帖子"
 | 
			
		||||
desktop/views/widgets/messaging.vue:
 | 
			
		||||
  title: "信息"
 | 
			
		||||
desktop/views/widgets/notifications.vue:
 | 
			
		||||
  title: "通知"
 | 
			
		||||
desktop/views/widgets/polls.vue:
 | 
			
		||||
@@ -1430,7 +1448,7 @@ mobile/views/components/note.vue:
 | 
			
		||||
  location: "位置信息"
 | 
			
		||||
mobile/views/components/note-detail.vue:
 | 
			
		||||
  reply: "回复"
 | 
			
		||||
  reaction: "反应"
 | 
			
		||||
  reaction: "回应"
 | 
			
		||||
  private: "这个帖子是私密的"
 | 
			
		||||
  deleted: "帖子已删除"
 | 
			
		||||
  location: "位置信息"
 | 
			
		||||
@@ -1488,7 +1506,7 @@ mobile/views/pages/home.vue:
 | 
			
		||||
  hybrid: "Social"
 | 
			
		||||
  global: "Global"
 | 
			
		||||
  mentions: "Mentions"
 | 
			
		||||
  messages: "信息"
 | 
			
		||||
  messages: "直接发布"
 | 
			
		||||
mobile/views/pages/tag.vue:
 | 
			
		||||
  no-posts-found: "没有找到带有主题标签“{q}”的帖子"
 | 
			
		||||
mobile/views/pages/widgets.vue:
 | 
			
		||||
@@ -1617,7 +1635,7 @@ dev/views/new-app.vue:
 | 
			
		||||
  account-read: "查看账户信息"
 | 
			
		||||
  account-write: "修改账户信息"
 | 
			
		||||
  note-write: "投稿。"
 | 
			
		||||
  reaction-write: "添加或删除反应。"
 | 
			
		||||
  reaction-write: "添加或删除回应。"
 | 
			
		||||
  following-write: "关注和不关注"
 | 
			
		||||
  drive-read: "查看网盘"
 | 
			
		||||
  drive-write: "管理网盘文件。"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										88
									
								
								locales/zh-TW.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								locales/zh-TW.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,88 @@
 | 
			
		||||
---
 | 
			
		||||
meta:
 | 
			
		||||
  lang: "中文(繁体)"
 | 
			
		||||
common:
 | 
			
		||||
  intro:
 | 
			
		||||
    title: "什麽是 Misskey 呢?"
 | 
			
		||||
    rich-contents: "發佈"
 | 
			
		||||
    reaction: "回應"
 | 
			
		||||
    drive: "雲端硬碟"
 | 
			
		||||
  adblock:
 | 
			
		||||
    detected: "請禁用廣告封鎖器"
 | 
			
		||||
  close: "關閉"
 | 
			
		||||
  enter-password: "請輸入密碼"
 | 
			
		||||
  2fa: "雙重身份驗證"
 | 
			
		||||
  dark-mode: "夜間模式"
 | 
			
		||||
  signup: "註冊"
 | 
			
		||||
  signout: "登出"
 | 
			
		||||
  notification:
 | 
			
		||||
    reversi-invited: "您已被邀請加入壹場遊戲"
 | 
			
		||||
    reversi-invited-by: "來自{}的邀請"
 | 
			
		||||
    notified-by: "來自{}的邀請"
 | 
			
		||||
  time:
 | 
			
		||||
    future: "未來"
 | 
			
		||||
    just_now: "剛剛"
 | 
			
		||||
  drive: "雲端硬碟"
 | 
			
		||||
  weekday:
 | 
			
		||||
    sunday: "週日"
 | 
			
		||||
    monday: "週一"
 | 
			
		||||
    tuesday: "週二"
 | 
			
		||||
    wednesday: "週三"
 | 
			
		||||
    thursday: "週四"
 | 
			
		||||
    friday: "週五"
 | 
			
		||||
    saturday: "週六"
 | 
			
		||||
  reactions:
 | 
			
		||||
    like: "贊"
 | 
			
		||||
    love: "喜歡"
 | 
			
		||||
    congrats: "恭喜"
 | 
			
		||||
  _settings:
 | 
			
		||||
    password: "密碼"
 | 
			
		||||
    font-size: "字體大小"
 | 
			
		||||
    font-size-x-small: "小"
 | 
			
		||||
    font-size-small: "較小"
 | 
			
		||||
    deck-column-width-wide: "寬"
 | 
			
		||||
    timeline: "時間軸"
 | 
			
		||||
common/views/components/connect-failed.troubleshooter.vue:
 | 
			
		||||
  flush: "清除快取"
 | 
			
		||||
common/views/components/theme.vue:
 | 
			
		||||
  light-themes: "淺色主題"
 | 
			
		||||
  dark-themes: "深色主題"
 | 
			
		||||
  install-a-theme: "安裝主題"
 | 
			
		||||
  save-created-theme: "保存主題"
 | 
			
		||||
common/views/components/signin.vue:
 | 
			
		||||
  signin-with-twitter: "用 Twitter 帳號登入"
 | 
			
		||||
  signin-with-github: "用 GitHub 帳號登入"
 | 
			
		||||
  signin-with-discord: "用 Discord 帳號登入"
 | 
			
		||||
  login-failed: "登錄失敗。 請檢查用戶名和密碼。"
 | 
			
		||||
common/views/components/signup.vue:
 | 
			
		||||
  invitation-code: "邀請碼"
 | 
			
		||||
  username: "用戶名"
 | 
			
		||||
  available: "可用"
 | 
			
		||||
  too-long: "請不要超過20個字元"
 | 
			
		||||
  password: "密碼"
 | 
			
		||||
  password-placeholder: "建議至少8個字元"
 | 
			
		||||
common/views/components/stream-indicator.vue:
 | 
			
		||||
  connecting: "正在連線"
 | 
			
		||||
  reconnecting: "正在重新連線"
 | 
			
		||||
  connected: "已建立連線"
 | 
			
		||||
common/views/components/integration-settings.vue:
 | 
			
		||||
  disconnect: "中斷連線"
 | 
			
		||||
common/views/components/github-setting.vue:
 | 
			
		||||
  reconnect: "重新連線"
 | 
			
		||||
  disconnect: "中斷連線"
 | 
			
		||||
common/views/components/discord-setting.vue:
 | 
			
		||||
  reconnect: "重新連線"
 | 
			
		||||
  disconnect: "中斷連線"
 | 
			
		||||
common/views/components/language-settings.vue:
 | 
			
		||||
  recommended: "推薦"
 | 
			
		||||
  auto: "自動"
 | 
			
		||||
  specify-language: "指定語言"
 | 
			
		||||
common/views/components/profile-editor.vue:
 | 
			
		||||
  title: "個人資料"
 | 
			
		||||
  name: "名稱"
 | 
			
		||||
  birthday: "生日:"
 | 
			
		||||
  privacy: "隱私"
 | 
			
		||||
admin/views/dashboard.vue:
 | 
			
		||||
  drive: "雲端硬碟"
 | 
			
		||||
admin/views/charts.vue:
 | 
			
		||||
  drive: "雲端硬碟"
 | 
			
		||||
							
								
								
									
										179
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										179
									
								
								package.json
									
									
									
									
									
								
							@@ -1,7 +1,7 @@
 | 
			
		||||
{
 | 
			
		||||
	"name": "misskey",
 | 
			
		||||
	"author": "syuilo <i@syuilo.com>",
 | 
			
		||||
	"version": "10.91.1",
 | 
			
		||||
	"version": "10.102.4",
 | 
			
		||||
	"codename": "nighthike",
 | 
			
		||||
	"repository": {
 | 
			
		||||
		"type": "git",
 | 
			
		||||
@@ -22,132 +22,136 @@
 | 
			
		||||
		"test": "gulp test",
 | 
			
		||||
		"format": "gulp format"
 | 
			
		||||
	},
 | 
			
		||||
	"resolutions": {
 | 
			
		||||
		"gulp-cssnano/cssnano/postcss-svgo/svgo/js-yaml": "^3.13.1",
 | 
			
		||||
		"video-thumbnail-generator/lodash": "^4.17.11"
 | 
			
		||||
	},
 | 
			
		||||
	"dependencies": {
 | 
			
		||||
		"@fortawesome/fontawesome-svg-core": "1.2.15",
 | 
			
		||||
		"@fortawesome/free-brands-svg-icons": "5.7.2",
 | 
			
		||||
		"@fortawesome/free-regular-svg-icons": "5.7.2",
 | 
			
		||||
		"@fortawesome/free-solid-svg-icons": "5.7.2",
 | 
			
		||||
		"@fortawesome/vue-fontawesome": "0.1.5",
 | 
			
		||||
		"@fortawesome/fontawesome-svg-core": "1.2.19",
 | 
			
		||||
		"@fortawesome/free-brands-svg-icons": "5.9.0",
 | 
			
		||||
		"@fortawesome/free-regular-svg-icons": "5.9.0",
 | 
			
		||||
		"@fortawesome/free-solid-svg-icons": "5.9.0",
 | 
			
		||||
		"@fortawesome/vue-fontawesome": "0.1.6",
 | 
			
		||||
		"@koa/cors": "2.2.3",
 | 
			
		||||
		"@prezzemolo/rap": "0.1.2",
 | 
			
		||||
		"@prezzemolo/zip": "0.0.3",
 | 
			
		||||
		"@types/bcryptjs": "2.4.2",
 | 
			
		||||
		"@types/bull": "3.5.14",
 | 
			
		||||
		"@types/chai-http": "3.0.5",
 | 
			
		||||
		"@types/dateformat": "3.0.0",
 | 
			
		||||
		"@types/deep-equal": "1.0.1",
 | 
			
		||||
		"@types/double-ended-queue": "2.1.0",
 | 
			
		||||
		"@types/elasticsearch": "5.0.30",
 | 
			
		||||
		"@types/file-type": "10.6.0",
 | 
			
		||||
		"@types/gulp": "4.0.5",
 | 
			
		||||
		"@types/elasticsearch": "5.0.34",
 | 
			
		||||
		"@types/gulp": "4.0.6",
 | 
			
		||||
		"@types/gulp-mocha": "0.0.32",
 | 
			
		||||
		"@types/gulp-rename": "0.0.33",
 | 
			
		||||
		"@types/gulp-replace": "0.0.31",
 | 
			
		||||
		"@types/gulp-uglify": "3.0.6",
 | 
			
		||||
		"@types/gulp-util": "3.0.34",
 | 
			
		||||
		"@types/is-root": "1.0.0",
 | 
			
		||||
		"@types/is-svg": "3.0.0",
 | 
			
		||||
		"@types/is-url": "1.2.28",
 | 
			
		||||
		"@types/js-yaml": "3.12.0",
 | 
			
		||||
		"@types/js-yaml": "3.12.1",
 | 
			
		||||
		"@types/jsdom": "12.2.3",
 | 
			
		||||
		"@types/katex": "0.10.1",
 | 
			
		||||
		"@types/koa": "2.0.48",
 | 
			
		||||
		"@types/koa-bodyparser": "5.0.2",
 | 
			
		||||
		"@types/koa-compress": "2.0.8",
 | 
			
		||||
		"@types/koa-compress": "2.0.9",
 | 
			
		||||
		"@types/koa-cors": "0.0.0",
 | 
			
		||||
		"@types/koa-favicon": "2.0.19",
 | 
			
		||||
		"@types/koa-logger": "3.1.1",
 | 
			
		||||
		"@types/koa-mount": "3.0.1",
 | 
			
		||||
		"@types/koa-multer": "1.0.0",
 | 
			
		||||
		"@types/koa-router": "7.0.39",
 | 
			
		||||
		"@types/koa-send": "4.1.1",
 | 
			
		||||
		"@types/koa-router": "7.0.40",
 | 
			
		||||
		"@types/koa-send": "4.1.2",
 | 
			
		||||
		"@types/koa-views": "2.0.3",
 | 
			
		||||
		"@types/koa__cors": "2.2.3",
 | 
			
		||||
		"@types/minio": "7.0.1",
 | 
			
		||||
		"@types/minio": "7.0.2",
 | 
			
		||||
		"@types/mkdirp": "0.5.2",
 | 
			
		||||
		"@types/mocha": "5.2.5",
 | 
			
		||||
		"@types/mongodb": "3.1.20",
 | 
			
		||||
		"@types/node": "10.12.24",
 | 
			
		||||
		"@types/nodemailer": "4.6.6",
 | 
			
		||||
		"@types/nprogress": "0.0.29",
 | 
			
		||||
		"@types/mocha": "5.2.7",
 | 
			
		||||
		"@types/mongodb": "3.1.28",
 | 
			
		||||
		"@types/node": "11.10.4",
 | 
			
		||||
		"@types/nodemailer": "6.2.0",
 | 
			
		||||
		"@types/nprogress": "0.2.0",
 | 
			
		||||
		"@types/oauth": "0.9.1",
 | 
			
		||||
		"@types/parse5": "5.0.0",
 | 
			
		||||
		"@types/parsimmon": "1.10.0",
 | 
			
		||||
		"@types/portscanner": "2.1.0",
 | 
			
		||||
		"@types/pug": "2.0.4",
 | 
			
		||||
		"@types/qrcode": "1.3.0",
 | 
			
		||||
		"@types/qrcode": "1.3.3",
 | 
			
		||||
		"@types/ratelimiter": "2.1.28",
 | 
			
		||||
		"@types/redis": "2.8.10",
 | 
			
		||||
		"@types/redis": "2.8.13",
 | 
			
		||||
		"@types/rename": "1.0.1",
 | 
			
		||||
		"@types/request": "2.48.1",
 | 
			
		||||
		"@types/request-promise-native": "1.0.15",
 | 
			
		||||
		"@types/request-promise-native": "1.0.16",
 | 
			
		||||
		"@types/request-stats": "3.0.0",
 | 
			
		||||
		"@types/rimraf": "2.0.2",
 | 
			
		||||
		"@types/seedrandom": "2.4.27",
 | 
			
		||||
		"@types/sharp": "0.21.2",
 | 
			
		||||
		"@types/seedrandom": "2.4.28",
 | 
			
		||||
		"@types/sharp": "0.22.2",
 | 
			
		||||
		"@types/showdown": "1.9.2",
 | 
			
		||||
		"@types/speakeasy": "2.0.3",
 | 
			
		||||
		"@types/speakeasy": "2.0.4",
 | 
			
		||||
		"@types/systeminformation": "3.23.1",
 | 
			
		||||
		"@types/tinycolor2": "1.4.1",
 | 
			
		||||
		"@types/tmp": "0.0.33",
 | 
			
		||||
		"@types/tinycolor2": "1.4.2",
 | 
			
		||||
		"@types/tmp": "0.1.0",
 | 
			
		||||
		"@types/uuid": "3.4.4",
 | 
			
		||||
		"@types/web-push": "3.3.0",
 | 
			
		||||
		"@types/webpack": "4.4.24",
 | 
			
		||||
		"@types/webpack": "4.4.32",
 | 
			
		||||
		"@types/webpack-stream": "3.2.10",
 | 
			
		||||
		"@types/websocket": "0.0.40",
 | 
			
		||||
		"@types/ws": "6.0.1",
 | 
			
		||||
		"animejs": "3.0.1",
 | 
			
		||||
		"apexcharts": "3.5.0",
 | 
			
		||||
		"apexcharts": "3.8.0",
 | 
			
		||||
		"autobind-decorator": "2.4.0",
 | 
			
		||||
		"autosize": "4.0.2",
 | 
			
		||||
		"autwh": "0.1.0",
 | 
			
		||||
		"bcryptjs": "2.4.3",
 | 
			
		||||
		"bee-queue": "1.2.2",
 | 
			
		||||
		"bootstrap-vue": "2.0.0-rc.11",
 | 
			
		||||
		"cafy": "15.1.0",
 | 
			
		||||
		"bootstrap-vue": "2.0.0-rc.22",
 | 
			
		||||
		"bull": "3.10.0",
 | 
			
		||||
		"cafy": "15.1.1",
 | 
			
		||||
		"chai": "4.2.0",
 | 
			
		||||
		"chai-http": "4.2.1",
 | 
			
		||||
		"chai-http": "4.3.0",
 | 
			
		||||
		"chalk": "2.4.2",
 | 
			
		||||
		"commander": "2.19.0",
 | 
			
		||||
		"commander": "2.20.0",
 | 
			
		||||
		"content-disposition": "0.5.3",
 | 
			
		||||
		"crc-32": "1.2.0",
 | 
			
		||||
		"css-loader": "2.1.0",
 | 
			
		||||
		"css-loader": "2.1.1",
 | 
			
		||||
		"cssnano": "4.1.10",
 | 
			
		||||
		"dateformat": "3.0.3",
 | 
			
		||||
		"deep-equal": "1.0.1",
 | 
			
		||||
		"deepcopy": "0.6.3",
 | 
			
		||||
		"diskusage": "1.0.0",
 | 
			
		||||
		"diskusage": "1.1.1",
 | 
			
		||||
		"double-ended-queue": "2.1.0-0",
 | 
			
		||||
		"elasticsearch": "15.3.1",
 | 
			
		||||
		"elasticsearch": "15.4.1",
 | 
			
		||||
		"emojilib": "2.4.0",
 | 
			
		||||
		"escape-regexp": "0.0.1",
 | 
			
		||||
		"eslint": "5.12.0",
 | 
			
		||||
		"eslint": "5.16.0",
 | 
			
		||||
		"eslint-plugin-vue": "5.2.2",
 | 
			
		||||
		"eventemitter3": "3.1.0",
 | 
			
		||||
		"feed": "2.0.2",
 | 
			
		||||
		"file-type": "10.7.1",
 | 
			
		||||
		"eventemitter3": "3.1.2",
 | 
			
		||||
		"feed": "2.0.4",
 | 
			
		||||
		"file-type": "10.10.0",
 | 
			
		||||
		"fuckadblock": "3.2.1",
 | 
			
		||||
		"gulp": "4.0.0",
 | 
			
		||||
		"gulp": "4.0.2",
 | 
			
		||||
		"gulp-cssnano": "2.1.3",
 | 
			
		||||
		"gulp-imagemin": "5.0.3",
 | 
			
		||||
		"gulp-mocha": "6.0.0",
 | 
			
		||||
		"gulp-rename": "1.4.0",
 | 
			
		||||
		"gulp-replace": "1.0.0",
 | 
			
		||||
		"gulp-sourcemaps": "2.6.4",
 | 
			
		||||
		"gulp-sourcemaps": "2.6.5",
 | 
			
		||||
		"gulp-stylus": "2.7.0",
 | 
			
		||||
		"gulp-tslint": "8.1.3",
 | 
			
		||||
		"gulp-typescript": "5.0.0",
 | 
			
		||||
		"gulp-uglify": "3.0.1",
 | 
			
		||||
		"gulp-tslint": "8.1.4",
 | 
			
		||||
		"gulp-typescript": "5.0.1",
 | 
			
		||||
		"gulp-uglify": "3.0.2",
 | 
			
		||||
		"gulp-util": "3.0.8",
 | 
			
		||||
		"gulp-yaml": "2.0.3",
 | 
			
		||||
		"hard-source-webpack-plugin": "0.13.1",
 | 
			
		||||
		"html-minifier": "3.5.21",
 | 
			
		||||
		"html-minifier": "4.0.0",
 | 
			
		||||
		"http-signature": "1.2.0",
 | 
			
		||||
		"insert-text-at-cursor": "0.1.2",
 | 
			
		||||
		"is-root": "2.0.0",
 | 
			
		||||
		"is-svg": "3.0.0",
 | 
			
		||||
		"js-yaml": "3.12.1",
 | 
			
		||||
		"jsdom": "13.2.0",
 | 
			
		||||
		"insert-text-at-cursor": "0.2.0",
 | 
			
		||||
		"is-root": "2.1.0",
 | 
			
		||||
		"is-svg": "4.2.0",
 | 
			
		||||
		"js-yaml": "3.13.1",
 | 
			
		||||
		"jsdom": "15.1.1",
 | 
			
		||||
		"json5": "2.1.0",
 | 
			
		||||
		"json5-loader": "1.0.1",
 | 
			
		||||
		"katex": "0.10.1",
 | 
			
		||||
		"json5-loader": "2.0.0",
 | 
			
		||||
		"katex": "0.10.2",
 | 
			
		||||
		"koa": "2.7.0",
 | 
			
		||||
		"koa-bodyparser": "4.2.1",
 | 
			
		||||
		"koa-compress": "3.0.0",
 | 
			
		||||
@@ -159,30 +163,29 @@
 | 
			
		||||
		"koa-router": "7.4.0",
 | 
			
		||||
		"koa-send": "5.0.0",
 | 
			
		||||
		"koa-slow": "2.1.0",
 | 
			
		||||
		"koa-views": "6.1.5",
 | 
			
		||||
		"koa-views": "6.2.0",
 | 
			
		||||
		"langmap": "0.0.16",
 | 
			
		||||
		"loader-utils": "1.2.3",
 | 
			
		||||
		"lookup-dns-cache": "2.1.0",
 | 
			
		||||
		"minio": "7.0.5",
 | 
			
		||||
		"minio": "7.0.8",
 | 
			
		||||
		"mkdirp": "0.5.1",
 | 
			
		||||
		"mocha": "5.2.0",
 | 
			
		||||
		"moji": "0.5.1",
 | 
			
		||||
		"moment": "2.24.0",
 | 
			
		||||
		"mongodb": "3.1.13",
 | 
			
		||||
		"mongodb": "3.2.7",
 | 
			
		||||
		"monk": "6.0.6",
 | 
			
		||||
		"ms": "2.1.1",
 | 
			
		||||
		"nan": "2.12.1",
 | 
			
		||||
		"ms": "2.1.2",
 | 
			
		||||
		"nan": "2.14.0",
 | 
			
		||||
		"nested-property": "0.0.7",
 | 
			
		||||
		"nodemailer": "5.1.1",
 | 
			
		||||
		"nprogress": "0.2.0",
 | 
			
		||||
		"object-assign-deep": "0.4.0",
 | 
			
		||||
		"on-build-webpack": "0.1.0",
 | 
			
		||||
		"os-utils": "0.0.14",
 | 
			
		||||
		"parse5": "5.1.0",
 | 
			
		||||
		"parsimmon": "1.12.0",
 | 
			
		||||
		"portscanner": "2.2.0",
 | 
			
		||||
		"postcss-loader": "3.0.0",
 | 
			
		||||
		"prismjs": "1.15.0",
 | 
			
		||||
		"prismjs": "1.16.0",
 | 
			
		||||
		"progress-bar-webpack-plugin": "1.12.1",
 | 
			
		||||
		"promise-any": "0.2.0",
 | 
			
		||||
		"promise-limit": "2.7.0",
 | 
			
		||||
@@ -190,19 +193,20 @@
 | 
			
		||||
		"pug": "2.0.3",
 | 
			
		||||
		"punycode": "2.1.1",
 | 
			
		||||
		"qrcode": "1.3.3",
 | 
			
		||||
		"randomcolor": "0.5.3",
 | 
			
		||||
		"ratelimiter": "3.2.0",
 | 
			
		||||
		"randomcolor": "0.5.4",
 | 
			
		||||
		"ratelimiter": "3.3.0",
 | 
			
		||||
		"recaptcha-promise": "0.1.3",
 | 
			
		||||
		"reconnecting-websocket": "4.1.10",
 | 
			
		||||
		"redis": "2.8.0",
 | 
			
		||||
		"rename": "1.0.4",
 | 
			
		||||
		"request": "2.88.0",
 | 
			
		||||
		"request-promise-native": "1.0.5",
 | 
			
		||||
		"request-promise-native": "1.0.7",
 | 
			
		||||
		"request-stats": "3.0.0",
 | 
			
		||||
		"rimraf": "2.6.3",
 | 
			
		||||
		"rndstr": "1.0.0",
 | 
			
		||||
		"s-age": "1.1.2",
 | 
			
		||||
		"seedrandom": "2.4.4",
 | 
			
		||||
		"sharp": "0.21.3",
 | 
			
		||||
		"sharp": "0.22.1",
 | 
			
		||||
		"showdown": "1.9.0",
 | 
			
		||||
		"showdown-highlightjs-extension": "0.1.2",
 | 
			
		||||
		"speakeasy": "2.0.0",
 | 
			
		||||
@@ -211,17 +215,17 @@
 | 
			
		||||
		"stylus": "0.54.5",
 | 
			
		||||
		"stylus-loader": "3.0.2",
 | 
			
		||||
		"summaly": "2.2.0",
 | 
			
		||||
		"systeminformation": "4.0.14",
 | 
			
		||||
		"systeminformation": "4.9.0",
 | 
			
		||||
		"syuilo-password-strength": "0.0.1",
 | 
			
		||||
		"terser-webpack-plugin": "1.2.3",
 | 
			
		||||
		"terser-webpack-plugin": "1.3.0",
 | 
			
		||||
		"textarea-caret": "3.1.0",
 | 
			
		||||
		"tinycolor2": "1.4.1",
 | 
			
		||||
		"tmp": "0.0.33",
 | 
			
		||||
		"tmp": "0.1.0",
 | 
			
		||||
		"ts-loader": "5.3.3",
 | 
			
		||||
		"ts-node": "8.0.2",
 | 
			
		||||
		"tslint": "5.13.1",
 | 
			
		||||
		"ts-node": "8.0.3",
 | 
			
		||||
		"tslint": "5.17.0",
 | 
			
		||||
		"tslint-sonarts": "1.9.0",
 | 
			
		||||
		"typescript": "3.3.3333",
 | 
			
		||||
		"typescript": "3.5.1",
 | 
			
		||||
		"typescript-eslint-parser": "22.0.0",
 | 
			
		||||
		"uglify-es": "3.3.9",
 | 
			
		||||
		"url-loader": "1.1.2",
 | 
			
		||||
@@ -229,31 +233,30 @@
 | 
			
		||||
		"v-animate-css": "0.0.3",
 | 
			
		||||
		"v-debounce": "0.1.2",
 | 
			
		||||
		"video-thumbnail-generator": "1.1.3",
 | 
			
		||||
		"vue": "2.6.8",
 | 
			
		||||
		"vue": "2.6.10",
 | 
			
		||||
		"vue-color": "2.7.0",
 | 
			
		||||
		"vue-content-loading": "1.5.3",
 | 
			
		||||
		"vue-content-loading": "1.6.0",
 | 
			
		||||
		"vue-cropperjs": "3.0.0",
 | 
			
		||||
		"vue-i18n": "8.8.2",
 | 
			
		||||
		"vue-js-modal": "1.3.28",
 | 
			
		||||
		"vue-json-viewer": "2.0.6",
 | 
			
		||||
		"vue-i18n": "8.11.2",
 | 
			
		||||
		"vue-js-modal": "1.3.31",
 | 
			
		||||
		"vue-json-pretty": "1.6.0",
 | 
			
		||||
		"vue-loader": "15.7.0",
 | 
			
		||||
		"vue-marquee-text-component": "1.1.1",
 | 
			
		||||
		"vue-prism-component": "1.1.1",
 | 
			
		||||
		"vue-router": "3.0.2",
 | 
			
		||||
		"vue-router": "3.0.6",
 | 
			
		||||
		"vue-sequential-entrance": "1.1.3",
 | 
			
		||||
		"vue-style-loader": "4.1.2",
 | 
			
		||||
		"vue-svg-inline-loader": "1.2.12",
 | 
			
		||||
		"vue-template-compiler": "2.6.8",
 | 
			
		||||
		"vuedraggable": "2.18.1",
 | 
			
		||||
		"vue-svg-inline-loader": "1.2.15",
 | 
			
		||||
		"vue-template-compiler": "2.6.10",
 | 
			
		||||
		"vuedraggable": "2.21.0",
 | 
			
		||||
		"vuewordcloud": "18.7.11",
 | 
			
		||||
		"vuex": "3.1.0",
 | 
			
		||||
		"vuex": "3.1.1",
 | 
			
		||||
		"vuex-persistedstate": "2.5.4",
 | 
			
		||||
		"web-push": "3.3.3",
 | 
			
		||||
		"webfinger.js": "2.7.0",
 | 
			
		||||
		"webpack": "4.28.4",
 | 
			
		||||
		"webpack-cli": "3.2.1",
 | 
			
		||||
		"web-push": "3.3.5",
 | 
			
		||||
		"webpack": "4.33.0",
 | 
			
		||||
		"webpack-cli": "3.3.3",
 | 
			
		||||
		"websocket": "1.0.28",
 | 
			
		||||
		"ws": "6.1.4",
 | 
			
		||||
		"ws": "6.2.1",
 | 
			
		||||
		"xev": "2.0.1"
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								src/@types/deepcopy.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								src/@types/deepcopy.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -1,17 +1,19 @@
 | 
			
		||||
declare module 'deepcopy';
 | 
			
		||||
 | 
			
		||||
declare namespace deepcopy {
 | 
			
		||||
declare module 'deepcopy' {
 | 
			
		||||
	type DeepcopyCustomizerValueType = 'Object';
 | 
			
		||||
 | 
			
		||||
	type DeepcopyCustomizer<T> = (
 | 
			
		||||
		value: T,
 | 
			
		||||
		valueType: DeepcopyCustomizerValueType) => T;
 | 
			
		||||
 | 
			
		||||
	interface DeepcopyOptions<T> {
 | 
			
		||||
	interface IDeepcopyOptions<T> {
 | 
			
		||||
		customizer: DeepcopyCustomizer<T>;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	export function deepcopy<T>(
 | 
			
		||||
	function deepcopy<T>(
 | 
			
		||||
		value: T,
 | 
			
		||||
		options?: DeepcopyOptions<T> | DeepcopyCustomizer<T>): T;
 | 
			
		||||
		options?: IDeepcopyOptions<T> | DeepcopyCustomizer<T>): T;
 | 
			
		||||
 | 
			
		||||
	namespace deepcopy {} // Hack
 | 
			
		||||
 | 
			
		||||
	export = deepcopy;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								src/@types/koa-slow.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								src/@types/koa-slow.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -8,7 +8,7 @@ declare module 'koa-slow' {
 | 
			
		||||
 | 
			
		||||
	function slow(options?: ISlowOptions): Middleware;
 | 
			
		||||
 | 
			
		||||
	namespace slow { } // Hack
 | 
			
		||||
	namespace slow {} // Hack
 | 
			
		||||
 | 
			
		||||
	export = slow;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										65
									
								
								src/@types/webfinger.js.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										65
									
								
								src/@types/webfinger.js.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -1,65 +0,0 @@
 | 
			
		||||
declare module 'webfinger.js' {
 | 
			
		||||
	interface IWebFingerConstructorConfig {
 | 
			
		||||
		tls_only?: boolean;
 | 
			
		||||
		webfist_fallback?: boolean;
 | 
			
		||||
		uri_fallback?: boolean;
 | 
			
		||||
		request_timeout?: number;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	type JRDProperties = { [type: string]: string };
 | 
			
		||||
 | 
			
		||||
	interface IJRDLink {
 | 
			
		||||
		rel: string;
 | 
			
		||||
		type?: string;
 | 
			
		||||
		href?: string;
 | 
			
		||||
		template?: string;
 | 
			
		||||
		titles?: { [lang: string]: string };
 | 
			
		||||
		properties?: JRDProperties;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	interface IJRD {
 | 
			
		||||
		subject?: string;
 | 
			
		||||
		expires?: Date;
 | 
			
		||||
		aliases?: string[];
 | 
			
		||||
		properties?: JRDProperties;
 | 
			
		||||
		links?: IJRDLink[];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	interface IIDXLinks {
 | 
			
		||||
		'avatar': IJRDLink[];
 | 
			
		||||
		'remotestorage': IJRDLink[];
 | 
			
		||||
		'blog': IJRDLink[];
 | 
			
		||||
		'vcard': IJRDLink[];
 | 
			
		||||
		'updates': IJRDLink[];
 | 
			
		||||
		'share': IJRDLink[];
 | 
			
		||||
		'profile': IJRDLink[];
 | 
			
		||||
		'webfist': IJRDLink[];
 | 
			
		||||
		'camlistore': IJRDLink[];
 | 
			
		||||
		[type: string]: IJRDLink[];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	interface IIDXProperties {
 | 
			
		||||
		'name': string;
 | 
			
		||||
		[type: string]: string;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	interface IIDX {
 | 
			
		||||
		links: IIDXLinks;
 | 
			
		||||
		properties: IIDXProperties;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	interface ILookupCallbackResult {
 | 
			
		||||
		object: IJRD;
 | 
			
		||||
		json: string;
 | 
			
		||||
		idx: IIDX;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	type LookupCallback = (err: Error | string, result?: ILookupCallbackResult) => void;
 | 
			
		||||
 | 
			
		||||
	export class WebFinger {
 | 
			
		||||
		constructor(config?: IWebFingerConstructorConfig);
 | 
			
		||||
 | 
			
		||||
		public lookup(address: string, cb: LookupCallback): NodeJS.Timeout;
 | 
			
		||||
		public lookupLink(address: string, rel: string, cb: IJRDLink): void;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -5,8 +5,7 @@ program
 | 
			
		||||
	.version(pkg.version)
 | 
			
		||||
	.option('--no-daemons', 'Disable daemon processes (for debbuging)')
 | 
			
		||||
	.option('--disable-clustering', 'Disable clustering')
 | 
			
		||||
	.option('--disable-queue', 'Disable job queue processing')
 | 
			
		||||
	.option('--only-server', 'Run server only (without job queue)')
 | 
			
		||||
	.option('--only-server', 'Run server only (without job queue processing)')
 | 
			
		||||
	.option('--only-queue', 'Pocessing job queue only (without server)')
 | 
			
		||||
	.option('--quiet', 'Suppress all logs')
 | 
			
		||||
	.option('--verbose', 'Enable all logs')
 | 
			
		||||
@@ -15,7 +14,6 @@ program
 | 
			
		||||
	.option('--color', 'This option is a dummy for some external program\'s (e.g. forever) issue.')
 | 
			
		||||
	.parse(process.argv);
 | 
			
		||||
 | 
			
		||||
/*if (process.env.MK_DISABLE_QUEUE)*/ program.disableQueue = true;
 | 
			
		||||
if (process.env.MK_ONLY_QUEUE) program.onlyQueue = true;
 | 
			
		||||
 | 
			
		||||
export { program };
 | 
			
		||||
 
 | 
			
		||||
@@ -181,7 +181,12 @@ export default Vue.extend({
 | 
			
		||||
				},
 | 
			
		||||
				grid: {
 | 
			
		||||
					clipMarkers: false,
 | 
			
		||||
					borderColor: 'rgba(0, 0, 0, 0.1)'
 | 
			
		||||
					borderColor: 'rgba(0, 0, 0, 0.1)',
 | 
			
		||||
					xaxis: {
 | 
			
		||||
						lines: {
 | 
			
		||||
							show: true,
 | 
			
		||||
						}
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
				stroke: {
 | 
			
		||||
					curve: 'straight',
 | 
			
		||||
@@ -240,6 +245,7 @@ export default Vue.extend({
 | 
			
		||||
		federationInstancesChart(total: boolean): any {
 | 
			
		||||
			return {
 | 
			
		||||
				series: [{
 | 
			
		||||
					name: 'Instances',
 | 
			
		||||
					data: this.format(total
 | 
			
		||||
						? this.stats.federation.instance.total
 | 
			
		||||
						: sum(this.stats.federation.instance.inc, negate(this.stats.federation.instance.dec))
 | 
			
		||||
							
								
								
									
										196
									
								
								src/client/app/admin/views/dashboard.queue-charts.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								src/client/app/admin/views/dashboard.queue-charts.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,196 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div class="mzxlfysy">
 | 
			
		||||
	<div>
 | 
			
		||||
		<header>
 | 
			
		||||
			<span><fa :icon="faInbox"/> In</span>
 | 
			
		||||
			<span v-if="latestStats">{{ latestStats.inbox.activeSincePrevTick | number }} / {{ latestStats.inbox.delayed | number }}</span>
 | 
			
		||||
		</header>
 | 
			
		||||
		<div ref="in"></div>
 | 
			
		||||
	</div>
 | 
			
		||||
	<div>
 | 
			
		||||
		<header>
 | 
			
		||||
			<span><fa :icon="faPaperPlane"/> Out</span>
 | 
			
		||||
			<span v-if="latestStats">{{ latestStats.deliver.activeSincePrevTick | number }} / {{ latestStats.deliver.delayed | number }}</span>
 | 
			
		||||
		</header>
 | 
			
		||||
		<div ref="out"></div>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import { faInbox } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import { faPaperPlane } from '@fortawesome/free-regular-svg-icons';
 | 
			
		||||
import ApexCharts from 'apexcharts';
 | 
			
		||||
 | 
			
		||||
const limit = 150;
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			stats: [],
 | 
			
		||||
			inChart: null,
 | 
			
		||||
			outChart: null,
 | 
			
		||||
			faInbox, faPaperPlane
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	computed: {
 | 
			
		||||
		latestStats(): any {
 | 
			
		||||
			return this.stats[this.stats.length - 1];
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	watch: {
 | 
			
		||||
		stats(stats) {
 | 
			
		||||
			this.inChart.updateSeries([{
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.inbox.activeSincePrevTick }))
 | 
			
		||||
			}, {
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.inbox.active }))
 | 
			
		||||
			}, {
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.inbox.waiting }))
 | 
			
		||||
			}, {
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.inbox.delayed }))
 | 
			
		||||
			}]);
 | 
			
		||||
			this.outChart.updateSeries([{
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.deliver.activeSincePrevTick }))
 | 
			
		||||
			}, {
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.deliver.active }))
 | 
			
		||||
			}, {
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.deliver.waiting }))
 | 
			
		||||
			}, {
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.deliver.delayed }))
 | 
			
		||||
			}]);
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	mounted() {
 | 
			
		||||
		const chartOpts = {
 | 
			
		||||
			chart: {
 | 
			
		||||
				type: 'area',
 | 
			
		||||
				height: 200,
 | 
			
		||||
				animations: {
 | 
			
		||||
					dynamicAnimation: {
 | 
			
		||||
						enabled: false
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				toolbar: {
 | 
			
		||||
					show: false
 | 
			
		||||
				},
 | 
			
		||||
				zoom: {
 | 
			
		||||
					enabled: false
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			dataLabels: {
 | 
			
		||||
				enabled: false
 | 
			
		||||
			},
 | 
			
		||||
			grid: {
 | 
			
		||||
				clipMarkers: false,
 | 
			
		||||
				borderColor: 'rgba(0, 0, 0, 0.1)'
 | 
			
		||||
			},
 | 
			
		||||
			stroke: {
 | 
			
		||||
				curve: 'straight',
 | 
			
		||||
				width: 2
 | 
			
		||||
			},
 | 
			
		||||
			tooltip: {
 | 
			
		||||
				enabled: false
 | 
			
		||||
			},
 | 
			
		||||
			legend: {
 | 
			
		||||
				show: false
 | 
			
		||||
			},
 | 
			
		||||
			colors: ['#00E396', '#00BCD4', '#FFB300', '#e53935'],
 | 
			
		||||
			series: [{ data: [] }, { data: [] }, { data: [] }, { data: [] }] as any,
 | 
			
		||||
			xaxis: {
 | 
			
		||||
				type: 'numeric',
 | 
			
		||||
				labels: {
 | 
			
		||||
					show: false
 | 
			
		||||
				},
 | 
			
		||||
				tooltip: {
 | 
			
		||||
					enabled: false
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			yaxis: {
 | 
			
		||||
				show: false,
 | 
			
		||||
				min: 0,
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		this.inChart = new ApexCharts(this.$refs.in, chartOpts);
 | 
			
		||||
		this.outChart = new ApexCharts(this.$refs.out, chartOpts);
 | 
			
		||||
 | 
			
		||||
		this.inChart.render();
 | 
			
		||||
		this.outChart.render();
 | 
			
		||||
 | 
			
		||||
		const connection = this.$root.stream.useSharedConnection('queueStats');
 | 
			
		||||
		connection.on('stats', this.onStats);
 | 
			
		||||
		connection.on('statsLog', this.onStatsLog);
 | 
			
		||||
		connection.send('requestLog', {
 | 
			
		||||
			id: Math.random().toString().substr(2, 8),
 | 
			
		||||
			length: limit
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		this.$once('hook:beforeDestroy', () => {
 | 
			
		||||
			connection.dispose();
 | 
			
		||||
			this.inChart.destroy();
 | 
			
		||||
			this.outChart.destroy();
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	methods: {
 | 
			
		||||
		onStats(stats) {
 | 
			
		||||
			this.stats.push(stats);
 | 
			
		||||
			if (this.stats.length > limit) this.stats.shift();
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		onStatsLog(statsLog) {
 | 
			
		||||
			for (const stats of statsLog.reverse()) {
 | 
			
		||||
				this.onStats(stats);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
.mzxlfysy
 | 
			
		||||
	display flex
 | 
			
		||||
 | 
			
		||||
	> div
 | 
			
		||||
		display block
 | 
			
		||||
		flex 1
 | 
			
		||||
		padding 20px 12px 0 12px
 | 
			
		||||
		box-shadow 0 2px 4px rgba(0, 0, 0, 0.1)
 | 
			
		||||
		background var(--face)
 | 
			
		||||
		border-radius 8px
 | 
			
		||||
 | 
			
		||||
		&:first-child
 | 
			
		||||
			margin-right 16px
 | 
			
		||||
 | 
			
		||||
		> header
 | 
			
		||||
			display flex
 | 
			
		||||
			padding 0 8px
 | 
			
		||||
			margin-bottom -16px
 | 
			
		||||
			color var(--adminDashboardCardFg)
 | 
			
		||||
			font-size 14px
 | 
			
		||||
 | 
			
		||||
			> span
 | 
			
		||||
				&:last-child
 | 
			
		||||
					margin-left auto
 | 
			
		||||
					opacity 0.7
 | 
			
		||||
 | 
			
		||||
				> span
 | 
			
		||||
					opacity 0.7
 | 
			
		||||
 | 
			
		||||
		> div
 | 
			
		||||
			margin-bottom -10px
 | 
			
		||||
 | 
			
		||||
	@media (max-width 1000px)
 | 
			
		||||
		display block
 | 
			
		||||
		margin-bottom 26px
 | 
			
		||||
 | 
			
		||||
		> div
 | 
			
		||||
			&:first-child
 | 
			
		||||
				margin-right 0
 | 
			
		||||
				margin-bottom 26px
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
@@ -73,6 +73,10 @@
 | 
			
		||||
		<x-charts ref="charts"/>
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
	<div class="queue">
 | 
			
		||||
		<x-queue/>
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
	<div class="cpu-memory">
 | 
			
		||||
		<x-cpu-memory :connection="connection"/>
 | 
			
		||||
	</div>
 | 
			
		||||
@@ -86,9 +90,10 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import i18n from '../../i18n';
 | 
			
		||||
import XCpuMemory from "./cpu-memory.vue";
 | 
			
		||||
import XCharts from "./charts.vue";
 | 
			
		||||
import XApLog from "./ap-log.vue";
 | 
			
		||||
import XCpuMemory from "./dashboard.cpu-memory.vue";
 | 
			
		||||
import XQueue from "./dashboard.queue-charts.vue";
 | 
			
		||||
import XCharts from "./dashboard.charts.vue";
 | 
			
		||||
import XApLog from "./dashboard.ap-log.vue";
 | 
			
		||||
import { faDatabase } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import MarqueeText from 'vue-marquee-text-component';
 | 
			
		||||
import randomColor from 'randomcolor';
 | 
			
		||||
@@ -98,6 +103,7 @@ export default Vue.extend({
 | 
			
		||||
 | 
			
		||||
	components: {
 | 
			
		||||
		XCpuMemory,
 | 
			
		||||
		XQueue,
 | 
			
		||||
		XCharts,
 | 
			
		||||
		XApLog,
 | 
			
		||||
		MarqueeText
 | 
			
		||||
@@ -274,6 +280,9 @@ export default Vue.extend({
 | 
			
		||||
	> .charts
 | 
			
		||||
		margin-bottom 16px
 | 
			
		||||
 | 
			
		||||
	> .queue
 | 
			
		||||
		margin-bottom 16px
 | 
			
		||||
 | 
			
		||||
	> .cpu-memory
 | 
			
		||||
		margin-bottom 16px
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@
 | 
			
		||||
				<div class="kidvdlkg" v-for="file in files">
 | 
			
		||||
					<div @click="file._open = !file._open">
 | 
			
		||||
						<div>
 | 
			
		||||
							<div class="thumbnail" :style="thumbnail(file)"></div>
 | 
			
		||||
							<x-file-thumbnail class="thumbnail" :file="file" fit="contain" @click="showFileMenu(file)"/>
 | 
			
		||||
						</div>
 | 
			
		||||
						<div>
 | 
			
		||||
							<header>
 | 
			
		||||
@@ -75,10 +75,15 @@ import Vue from 'vue';
 | 
			
		||||
import i18n from '../../i18n';
 | 
			
		||||
import { faCloud, faTerminal, faSearch } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import { faTrashAlt, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
 | 
			
		||||
import XFileThumbnail from '../../common/views/components/drive-file-thumbnail.vue';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	i18n: i18n('admin/views/drive.vue'),
 | 
			
		||||
 | 
			
		||||
	components: {
 | 
			
		||||
		XFileThumbnail
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			file: null,
 | 
			
		||||
@@ -151,13 +156,6 @@ export default Vue.extend({
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		thumbnail(file: any): any {
 | 
			
		||||
			return {
 | 
			
		||||
				'background-color': file.properties.avgColor && file.properties.avgColor.length == 3 ? `rgb(${file.properties.avgColor.join(',')})` : 'transparent',
 | 
			
		||||
				'background-image': `url(${file.thumbnailUrl})`
 | 
			
		||||
			};
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		async del(file: any) {
 | 
			
		||||
			const process = async () => {
 | 
			
		||||
				await this.$root.api('drive/files/delete', { fileId: file.id });
 | 
			
		||||
@@ -179,9 +177,9 @@ export default Vue.extend({
 | 
			
		||||
			this.$root.api('drive/files/update', {
 | 
			
		||||
				fileId: file.id,
 | 
			
		||||
				isSensitive: !file.isSensitive
 | 
			
		||||
			}).then(() => {
 | 
			
		||||
				file.isSensitive = !file.isSensitive;
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			file.isSensitive = !file.isSensitive;
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		async show() {
 | 
			
		||||
@@ -244,7 +242,7 @@ export default Vue.extend({
 | 
			
		||||
 | 
			
		||||
		> div:nth-child(1)
 | 
			
		||||
			> .thumbnail
 | 
			
		||||
				display block
 | 
			
		||||
				display flex
 | 
			
		||||
				width 64px
 | 
			
		||||
				height 64px
 | 
			
		||||
				background-size cover
 | 
			
		||||
 
 | 
			
		||||
@@ -1,43 +1,58 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div>
 | 
			
		||||
	<ui-card>
 | 
			
		||||
		<template #title><fa :icon="faTerminal"/> {{ $t('federation') }}</template>
 | 
			
		||||
		<template #title><fa :icon="faTerminal"/> {{ $t('instance') }}</template>
 | 
			
		||||
		<section class="fit-top">
 | 
			
		||||
			<ui-input class="target" v-model="target" type="text" @enter="showInstance()">
 | 
			
		||||
				<span>{{ $t('host') }}</span>
 | 
			
		||||
				<template #prefix><fa :icon="faServer"/></template>
 | 
			
		||||
			</ui-input>
 | 
			
		||||
			<ui-button @click="showInstance()"><fa :icon="faSearch"/> {{ $t('lookup') }}</ui-button>
 | 
			
		||||
 | 
			
		||||
			<div class="instance" v-if="instance">
 | 
			
		||||
				<ui-input :value="instance.host" type="text" readonly>
 | 
			
		||||
					<span>{{ $t('host') }}</span>
 | 
			
		||||
				</ui-input>
 | 
			
		||||
				<ui-horizon-group inputs>
 | 
			
		||||
					<ui-input :value="instance.host" type="text" readonly>
 | 
			
		||||
						<span>{{ $t('host') }}</span>
 | 
			
		||||
						<template #prefix><fa :icon="faServer"/></template>
 | 
			
		||||
					</ui-input>
 | 
			
		||||
					<ui-input :value="instance.caughtAt | date" type="text" readonly>
 | 
			
		||||
						<span>{{ $t('caught-at') }}</span>
 | 
			
		||||
						<template #prefix><fa :icon="faCrosshairs"/></template>
 | 
			
		||||
					</ui-input>
 | 
			
		||||
				</ui-horizon-group>
 | 
			
		||||
				<ui-horizon-group inputs>
 | 
			
		||||
					<ui-input :value="instance.notesCount | number" type="text" readonly>
 | 
			
		||||
						<span>{{ $t('notes') }}</span>
 | 
			
		||||
						<template #prefix><fa :icon="faEnvelopeOpenText"/></template>
 | 
			
		||||
					</ui-input>
 | 
			
		||||
					<ui-input :value="instance.usersCount | number" type="text" readonly>
 | 
			
		||||
						<span>{{ $t('users') }}</span>
 | 
			
		||||
						<template #prefix><fa :icon="faUsers"/></template>
 | 
			
		||||
					</ui-input>
 | 
			
		||||
				</ui-horizon-group>
 | 
			
		||||
				<ui-horizon-group inputs>
 | 
			
		||||
					<ui-input :value="instance.followingCount | number" type="text" readonly>
 | 
			
		||||
						<span>{{ $t('following') }}</span>
 | 
			
		||||
						<template #prefix><fa :icon="faCaretDown"/></template>
 | 
			
		||||
					</ui-input>
 | 
			
		||||
					<ui-input :value="instance.followersCount | number" type="text" readonly>
 | 
			
		||||
						<span>{{ $t('followers') }}</span>
 | 
			
		||||
						<template #prefix><fa :icon="faCaretUp"/></template>
 | 
			
		||||
					</ui-input>
 | 
			
		||||
				</ui-horizon-group>
 | 
			
		||||
				<ui-horizon-group inputs>
 | 
			
		||||
					<ui-input :value="instance.latestRequestSentAt" type="text" readonly>
 | 
			
		||||
					<ui-input :value="instance.latestRequestSentAt | date" type="text" readonly>
 | 
			
		||||
						<span>{{ $t('latest-request-sent-at') }}</span>
 | 
			
		||||
						<template #prefix><fa :icon="faPaperPlane"/></template>
 | 
			
		||||
					</ui-input>
 | 
			
		||||
					<ui-input :value="instance.latestStatus" type="text" readonly>
 | 
			
		||||
						<span>{{ $t('status') }}</span>
 | 
			
		||||
						<template #prefix><fa :icon="faTrafficLight"/></template>
 | 
			
		||||
					</ui-input>
 | 
			
		||||
				</ui-horizon-group>
 | 
			
		||||
				<ui-input :value="instance.latestRequestReceivedAt" type="text" readonly>
 | 
			
		||||
				<ui-input :value="instance.latestRequestReceivedAt | date" type="text" readonly>
 | 
			
		||||
					<span>{{ $t('latest-request-received-at') }}</span>
 | 
			
		||||
					<template #prefix><fa :icon="faInbox"/></template>
 | 
			
		||||
				</ui-input>
 | 
			
		||||
				<ui-switch v-model="instance.isBlocked" @change="updateInstance()">{{ $t('block') }}</ui-switch>
 | 
			
		||||
				<ui-switch v-model="instance.isMarkedAsClosed" @change="updateInstance()">{{ $t('marked-as-closed') }}</ui-switch>
 | 
			
		||||
@@ -115,7 +130,7 @@
 | 
			
		||||
					<span>{{ $t('status') }}</span>
 | 
			
		||||
				</header>
 | 
			
		||||
				<div v-for="instance in instances" :style="{ opacity: instance.isNotResponding ? 0.5 : 1 }">
 | 
			
		||||
					<a @click.prevent="showInstance(instance.host)" target="_blank" :href="`https://${instance.host}`" :style="{ textDecoration: instance.isMarkedAsClosed ? 'line-through' : 'none' }">{{ instance.host }}</a>
 | 
			
		||||
					<a @click.prevent="showInstance(instance.host)" rel="nofollow noopener" target="_blank" :href="`https://${instance.host}`" :style="{ textDecoration: instance.isMarkedAsClosed ? 'line-through' : 'none' }">{{ instance.host }}</a>
 | 
			
		||||
					<span>{{ instance.notesCount | number }}</span>
 | 
			
		||||
					<span>{{ instance.usersCount | number }}</span>
 | 
			
		||||
					<span>{{ instance.followingCount | number }}</span>
 | 
			
		||||
@@ -133,7 +148,8 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import i18n from '../../i18n';
 | 
			
		||||
import { faGlobe, faTerminal, faSearch, faMinusCircle, faServer } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import { faPaperPlane } from '@fortawesome/free-regular-svg-icons';
 | 
			
		||||
import { faGlobe, faTerminal, faSearch, faMinusCircle, faServer, faCrosshairs, faEnvelopeOpenText, faUsers, faCaretDown, faCaretUp, faTrafficLight, faInbox } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import ApexCharts from 'apexcharts';
 | 
			
		||||
import * as tinycolor from 'tinycolor2';
 | 
			
		||||
 | 
			
		||||
@@ -144,19 +160,23 @@ const negate = arr => arr.map(x => -x);
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	i18n: i18n('admin/views/federation.vue'),
 | 
			
		||||
 | 
			
		||||
	filters: {
 | 
			
		||||
		date: v => v ? new Date(v).toLocaleString() : 'N/A'
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			instance: null,
 | 
			
		||||
			target: null,
 | 
			
		||||
			sort: '+lastCommunicatedAt',
 | 
			
		||||
			state: 'all',
 | 
			
		||||
			limit: 50,
 | 
			
		||||
			limit: 100,
 | 
			
		||||
			instances: [],
 | 
			
		||||
			chart: null,
 | 
			
		||||
			chartSrc: 'requests',
 | 
			
		||||
			chartSpan: 'hour',
 | 
			
		||||
			chartInstance: null,
 | 
			
		||||
			faGlobe, faTerminal, faSearch, faMinusCircle, faServer
 | 
			
		||||
			faGlobe, faTerminal, faSearch, faMinusCircle, faServer, faCrosshairs, faEnvelopeOpenText, faUsers, faCaretDown, faCaretUp, faPaperPlane, faTrafficLight, faInbox
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@
 | 
			
		||||
			<ui-input :value="host" readonly>{{ $t('host') }}</ui-input>
 | 
			
		||||
			<ui-input v-model="name">{{ $t('instance-name') }}</ui-input>
 | 
			
		||||
			<ui-textarea v-model="description">{{ $t('instance-description') }}</ui-textarea>
 | 
			
		||||
			<ui-input v-model="iconUrl"><template #icon><fa icon="link"/></template>{{ $t('icon-url') }}</ui-input>
 | 
			
		||||
			<ui-input v-model="mascotImageUrl"><template #icon><fa icon="link"/></template>{{ $t('logo-url') }}</ui-input>
 | 
			
		||||
			<ui-input v-model="bannerUrl"><template #icon><fa icon="link"/></template>{{ $t('banner-url') }}</ui-input>
 | 
			
		||||
			<ui-input v-model="errorImageUrl"><template #icon><fa icon="link"/></template>{{ $t('error-image-url') }}</ui-input>
 | 
			
		||||
@@ -24,6 +25,8 @@
 | 
			
		||||
			<ui-switch v-model="disableLocalTimeline">{{ $t('disable-local-timeline') }}</ui-switch>
 | 
			
		||||
			<ui-switch v-model="disableGlobalTimeline">{{ $t('disable-global-timeline') }}</ui-switch>
 | 
			
		||||
			<ui-info>{{ $t('disabling-timelines-info') }}</ui-info>
 | 
			
		||||
			<ui-switch v-model="enableEmojiReaction">{{ $t('enable-emoji-reaction') }}</ui-switch>
 | 
			
		||||
			<ui-switch v-model="useStarForReactionFallback">{{ $t('use-star-for-reaction-fallback') }}</ui-switch>
 | 
			
		||||
		</section>
 | 
			
		||||
		<section class="fit-bottom">
 | 
			
		||||
			<header><fa icon="cloud"/> {{ $t('drive-config') }}</header>
 | 
			
		||||
@@ -154,9 +157,12 @@ export default Vue.extend({
 | 
			
		||||
			disableRegistration: false,
 | 
			
		||||
			disableLocalTimeline: false,
 | 
			
		||||
			disableGlobalTimeline: false,
 | 
			
		||||
			enableEmojiReaction: true,
 | 
			
		||||
			useStarForReactionFallback: false,
 | 
			
		||||
			mascotImageUrl: null,
 | 
			
		||||
			bannerUrl: null,
 | 
			
		||||
			errorImageUrl: null,
 | 
			
		||||
			iconUrl: null,
 | 
			
		||||
			name: null,
 | 
			
		||||
			description: null,
 | 
			
		||||
			languages: null,
 | 
			
		||||
@@ -204,9 +210,12 @@ export default Vue.extend({
 | 
			
		||||
			this.disableRegistration = meta.disableRegistration;
 | 
			
		||||
			this.disableLocalTimeline = meta.disableLocalTimeline;
 | 
			
		||||
			this.disableGlobalTimeline = meta.disableGlobalTimeline;
 | 
			
		||||
			this.enableEmojiReaction = meta.enableEmojiReaction;
 | 
			
		||||
			this.useStarForReactionFallback = meta.useStarForReactionFallback;
 | 
			
		||||
			this.mascotImageUrl = meta.mascotImageUrl;
 | 
			
		||||
			this.bannerUrl = meta.bannerUrl;
 | 
			
		||||
			this.errorImageUrl = meta.errorImageUrl;
 | 
			
		||||
			this.iconUrl = meta.iconUrl;
 | 
			
		||||
			this.name = meta.name;
 | 
			
		||||
			this.description = meta.description;
 | 
			
		||||
			this.languages = meta.langs.join(' ');
 | 
			
		||||
@@ -264,9 +273,12 @@ export default Vue.extend({
 | 
			
		||||
				disableRegistration: this.disableRegistration,
 | 
			
		||||
				disableLocalTimeline: this.disableLocalTimeline,
 | 
			
		||||
				disableGlobalTimeline: this.disableGlobalTimeline,
 | 
			
		||||
				enableEmojiReaction: this.enableEmojiReaction,
 | 
			
		||||
				useStarForReactionFallback: this.useStarForReactionFallback,
 | 
			
		||||
				mascotImageUrl: this.mascotImageUrl,
 | 
			
		||||
				bannerUrl: this.bannerUrl,
 | 
			
		||||
				errorImageUrl: this.errorImageUrl,
 | 
			
		||||
				iconUrl: this.iconUrl,
 | 
			
		||||
				name: this.name,
 | 
			
		||||
				description: this.description,
 | 
			
		||||
				langs: this.languages.split(' '),
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
		<template #title><fa :icon="faStream"/> {{ $t('logs') }}</template>
 | 
			
		||||
		<section class="fit-top">
 | 
			
		||||
			<ui-horizon-group inputs>
 | 
			
		||||
				<ui-input v-model="domain" debounce>
 | 
			
		||||
				<ui-input v-model="domain" :debounce="true">
 | 
			
		||||
					<span>{{ $t('domain') }}</span>
 | 
			
		||||
				</ui-input>
 | 
			
		||||
				<ui-select v-model="level">
 | 
			
		||||
@@ -22,7 +22,7 @@
 | 
			
		||||
				<code v-for="log in logs" :key="log._id" :class="log.level">
 | 
			
		||||
					<details>
 | 
			
		||||
						<summary><mk-time :time="log.createdAt"/> [{{ log.domain.join('.') }}] {{ log.message }}</summary>
 | 
			
		||||
						<json-viewer v-if="log.data" :value="log.data"></json-viewer>
 | 
			
		||||
						<vue-json-pretty v-if="log.data" :data="log.data"></vue-json-pretty>
 | 
			
		||||
					</details>
 | 
			
		||||
				</code>
 | 
			
		||||
			</div>
 | 
			
		||||
@@ -35,13 +35,13 @@
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import i18n from '../../i18n';
 | 
			
		||||
import { faStream } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import JsonViewer from 'vue-json-viewer';
 | 
			
		||||
import VueJsonPretty from 'vue-json-pretty';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	i18n: i18n('admin/views/logs.vue'),
 | 
			
		||||
 | 
			
		||||
	components: {
 | 
			
		||||
		JsonViewer
 | 
			
		||||
		VueJsonPretty
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	data() {
 | 
			
		||||
@@ -85,11 +85,10 @@ export default Vue.extend({
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
.nqjzuvev
 | 
			
		||||
	white-space nowrap
 | 
			
		||||
	overflow auto
 | 
			
		||||
	padding 8px
 | 
			
		||||
	background #000
 | 
			
		||||
	color #fff
 | 
			
		||||
	font-size 14px
 | 
			
		||||
 | 
			
		||||
	> code
 | 
			
		||||
		display block
 | 
			
		||||
 
 | 
			
		||||
@@ -1,26 +1,261 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div>
 | 
			
		||||
	<ui-card>
 | 
			
		||||
		<template #title>{{ $t('operation') }}</template>
 | 
			
		||||
		<template #title><fa :icon="faChartBar"/> {{ $t('title') }}</template>
 | 
			
		||||
		<section class="wptihjuy">
 | 
			
		||||
			<header><fa :icon="faPaperPlane"/> Deliver</header>
 | 
			
		||||
			<ui-info warn v-if="latestStats && latestStats.deliver.waiting > 0">The queue is jammed.</ui-info>
 | 
			
		||||
			<ui-horizon-group inputs v-if="latestStats" class="fit-bottom">
 | 
			
		||||
				<ui-input :value="latestStats.deliver.activeSincePrevTick | number" type="text" readonly>
 | 
			
		||||
					<span>Process</span>
 | 
			
		||||
					<template #prefix><fa :icon="fasPlayCircle"/></template>
 | 
			
		||||
					<template #suffix>jobs/tick</template>
 | 
			
		||||
				</ui-input>
 | 
			
		||||
				<ui-input :value="latestStats.deliver.active | number" type="text" readonly>
 | 
			
		||||
					<span>Active</span>
 | 
			
		||||
					<template #prefix><fa :icon="farPlayCircle"/></template>
 | 
			
		||||
					<template #suffix>jobs</template>
 | 
			
		||||
				</ui-input>
 | 
			
		||||
				<ui-input :value="latestStats.deliver.waiting | number" type="text" readonly>
 | 
			
		||||
					<span>Waiting</span>
 | 
			
		||||
					<template #prefix><fa :icon="faStopCircle"/></template>
 | 
			
		||||
					<template #suffix>jobs</template>
 | 
			
		||||
				</ui-input>
 | 
			
		||||
				<ui-input :value="latestStats.deliver.delayed | number" type="text" readonly>
 | 
			
		||||
					<span>Delayed</span>
 | 
			
		||||
					<template #prefix><fa :icon="faStopwatch"/></template>
 | 
			
		||||
					<template #suffix>jobs</template>
 | 
			
		||||
				</ui-input>
 | 
			
		||||
			</ui-horizon-group>
 | 
			
		||||
			<div ref="deliverChart" class="chart"></div>
 | 
			
		||||
		</section>
 | 
			
		||||
		<section class="wptihjuy">
 | 
			
		||||
			<header><fa :icon="faInbox"/> Inbox</header>
 | 
			
		||||
			<ui-info warn v-if="latestStats && latestStats.inbox.waiting > 0">The queue is jammed.</ui-info>
 | 
			
		||||
			<ui-horizon-group inputs v-if="latestStats" class="fit-bottom">
 | 
			
		||||
				<ui-input :value="latestStats.inbox.activeSincePrevTick | number" type="text" readonly>
 | 
			
		||||
					<span>Process</span>
 | 
			
		||||
					<template #prefix><fa :icon="fasPlayCircle"/></template>
 | 
			
		||||
					<template #suffix>jobs/tick</template>
 | 
			
		||||
				</ui-input>
 | 
			
		||||
				<ui-input :value="latestStats.inbox.active | number" type="text" readonly>
 | 
			
		||||
					<span>Active</span>
 | 
			
		||||
					<template #prefix><fa :icon="farPlayCircle"/></template>
 | 
			
		||||
					<template #suffix>jobs</template>
 | 
			
		||||
				</ui-input>
 | 
			
		||||
				<ui-input :value="latestStats.inbox.waiting | number" type="text" readonly>
 | 
			
		||||
					<span>Waiting</span>
 | 
			
		||||
					<template #prefix><fa :icon="faStopCircle"/></template>
 | 
			
		||||
					<template #suffix>jobs</template>
 | 
			
		||||
				</ui-input>
 | 
			
		||||
				<ui-input :value="latestStats.inbox.delayed | number" type="text" readonly>
 | 
			
		||||
					<span>Delayed</span>
 | 
			
		||||
					<template #prefix><fa :icon="faStopwatch"/></template>
 | 
			
		||||
					<template #suffix>jobs</template>
 | 
			
		||||
				</ui-input>
 | 
			
		||||
			</ui-horizon-group>
 | 
			
		||||
			<div ref="inboxChart" class="chart"></div>
 | 
			
		||||
		</section>
 | 
			
		||||
		<section>
 | 
			
		||||
			<ui-button @click="removeAllJobs">{{ $t('remove-all-jobs') }}</ui-button>
 | 
			
		||||
		</section>
 | 
			
		||||
	</ui-card>
 | 
			
		||||
 | 
			
		||||
	<ui-card>
 | 
			
		||||
		<template #title><fa :icon="faTasks"/> {{ $t('jobs') }}</template>
 | 
			
		||||
		<section class="fit-top">
 | 
			
		||||
			<ui-horizon-group inputs>
 | 
			
		||||
				<ui-select v-model="domain">
 | 
			
		||||
					<template #label>{{ $t('queue') }}</template>
 | 
			
		||||
					<option value="deliver">{{ $t('domains.deliver') }}</option>
 | 
			
		||||
					<option value="inbox">{{ $t('domains.inbox') }}</option>
 | 
			
		||||
				</ui-select>
 | 
			
		||||
				<ui-select v-model="state">
 | 
			
		||||
					<template #label>{{ $t('state') }}</template>
 | 
			
		||||
					<option value="delayed">{{ $t('states.delayed') }}</option>
 | 
			
		||||
				</ui-select>
 | 
			
		||||
			</ui-horizon-group>
 | 
			
		||||
			<sequential-entrance animation="entranceFromTop" delay="25">
 | 
			
		||||
				<div class="xvvuvgsv" v-for="job in jobs">
 | 
			
		||||
					<b>{{ job.id }}</b>
 | 
			
		||||
					<template v-if="domain === 'deliver'">
 | 
			
		||||
						<span>{{ job.data.to }}</span>
 | 
			
		||||
					</template>
 | 
			
		||||
					<template v-if="domain === 'inbox'">
 | 
			
		||||
						<span>{{ job.activity.id }}</span>
 | 
			
		||||
					</template>
 | 
			
		||||
				</div>
 | 
			
		||||
			</sequential-entrance>
 | 
			
		||||
			<ui-info v-if="jobs.length == jobsLimit">{{ $t('result-is-truncated', { n: jobsLimit }) }}</ui-info>
 | 
			
		||||
		</section>
 | 
			
		||||
	</ui-card>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import i18n from '../../i18n';
 | 
			
		||||
import ApexCharts from 'apexcharts';
 | 
			
		||||
import * as tinycolor from 'tinycolor2';
 | 
			
		||||
import { faTasks, faInbox, faStopwatch, faPlayCircle as fasPlayCircle } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import { faPaperPlane, faStopCircle, faPlayCircle as farPlayCircle, faChartBar } from '@fortawesome/free-regular-svg-icons';
 | 
			
		||||
 | 
			
		||||
const limit = 200;
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	i18n: i18n('admin/views/queue.vue'),
 | 
			
		||||
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			stats: [],
 | 
			
		||||
			deliverChart: null,
 | 
			
		||||
			inboxChart: null,
 | 
			
		||||
			jobs: [],
 | 
			
		||||
			jobsLimit: 50,
 | 
			
		||||
			domain: 'deliver',
 | 
			
		||||
			state: 'delayed',
 | 
			
		||||
			faTasks, faPaperPlane, faInbox, faStopwatch, faStopCircle, farPlayCircle, fasPlayCircle, faChartBar
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	computed: {
 | 
			
		||||
		latestStats(): any {
 | 
			
		||||
			return this.stats[this.stats.length - 1];
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	watch: {
 | 
			
		||||
		stats(stats) {
 | 
			
		||||
			this.inboxChart.updateSeries([{
 | 
			
		||||
				name: 'Process',
 | 
			
		||||
				type: 'area',
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.inbox.activeSincePrevTick }))
 | 
			
		||||
			}, {
 | 
			
		||||
				name: 'Active',
 | 
			
		||||
				type: 'area',
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.inbox.active }))
 | 
			
		||||
			}, {
 | 
			
		||||
				name: 'Waiting',
 | 
			
		||||
				type: 'line',
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.inbox.waiting }))
 | 
			
		||||
			}, {
 | 
			
		||||
				name: 'Delayed',
 | 
			
		||||
				type: 'line',
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.inbox.delayed }))
 | 
			
		||||
			}]);
 | 
			
		||||
			this.deliverChart.updateSeries([{
 | 
			
		||||
				name: 'Process',
 | 
			
		||||
				type: 'area',
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.deliver.activeSincePrevTick }))
 | 
			
		||||
			}, {
 | 
			
		||||
				name: 'Active',
 | 
			
		||||
				type: 'area',
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.deliver.active }))
 | 
			
		||||
			}, {
 | 
			
		||||
				name: 'Waiting',
 | 
			
		||||
				type: 'line',
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.deliver.waiting }))
 | 
			
		||||
			}, {
 | 
			
		||||
				name: 'Delayed',
 | 
			
		||||
				type: 'line',
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.deliver.delayed }))
 | 
			
		||||
			}]);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		domain() {
 | 
			
		||||
			this.jobs = [];
 | 
			
		||||
			this.fetchJobs();
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		state() {
 | 
			
		||||
			this.jobs = [];
 | 
			
		||||
			this.fetchJobs();
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.fetchJobs();
 | 
			
		||||
 | 
			
		||||
		const chartOpts = id => ({
 | 
			
		||||
			chart: {
 | 
			
		||||
				id,
 | 
			
		||||
				group: 'queue',
 | 
			
		||||
				type: 'area',
 | 
			
		||||
				height: 200,
 | 
			
		||||
				animations: {
 | 
			
		||||
					dynamicAnimation: {
 | 
			
		||||
						enabled: false
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				toolbar: {
 | 
			
		||||
					show: false
 | 
			
		||||
				},
 | 
			
		||||
				zoom: {
 | 
			
		||||
					enabled: false
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			dataLabels: {
 | 
			
		||||
				enabled: false
 | 
			
		||||
			},
 | 
			
		||||
			grid: {
 | 
			
		||||
				clipMarkers: false,
 | 
			
		||||
				borderColor: 'rgba(0, 0, 0, 0.1)',
 | 
			
		||||
				xaxis: {
 | 
			
		||||
					lines: {
 | 
			
		||||
						show: true,
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			stroke: {
 | 
			
		||||
				curve: 'straight',
 | 
			
		||||
				width: 2
 | 
			
		||||
			},
 | 
			
		||||
			tooltip: {
 | 
			
		||||
				enabled: false
 | 
			
		||||
			},
 | 
			
		||||
			legend: {
 | 
			
		||||
				labels: {
 | 
			
		||||
					colors: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--text')).toRgbString()
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			series: [] as any,
 | 
			
		||||
			colors: ['#00E396', '#00BCD4', '#FFB300', '#e53935'],
 | 
			
		||||
			xaxis: {
 | 
			
		||||
				type: 'numeric',
 | 
			
		||||
				labels: {
 | 
			
		||||
					show: false
 | 
			
		||||
				},
 | 
			
		||||
				tooltip: {
 | 
			
		||||
					enabled: false
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			yaxis: {
 | 
			
		||||
				show: false,
 | 
			
		||||
				min: 0,
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		this.inboxChart = new ApexCharts(this.$refs.inboxChart, chartOpts('a'));
 | 
			
		||||
		this.deliverChart = new ApexCharts(this.$refs.deliverChart, chartOpts('b'));
 | 
			
		||||
 | 
			
		||||
		this.inboxChart.render();
 | 
			
		||||
		this.deliverChart.render();
 | 
			
		||||
 | 
			
		||||
		const connection = this.$root.stream.useSharedConnection('queueStats');
 | 
			
		||||
		connection.on('stats', this.onStats);
 | 
			
		||||
		connection.on('statsLog', this.onStatsLog);
 | 
			
		||||
		connection.send('requestLog', {
 | 
			
		||||
			id: Math.random().toString().substr(2, 8),
 | 
			
		||||
			length: limit
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		this.$once('hook:beforeDestroy', () => {
 | 
			
		||||
			connection.dispose();
 | 
			
		||||
			this.inboxChart.destroy();
 | 
			
		||||
			this.deliverChart.destroy();
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	methods: {
 | 
			
		||||
		async removeAllJobs() {
 | 
			
		||||
			const process = async () => {
 | 
			
		||||
@@ -38,6 +273,39 @@ export default Vue.extend({
 | 
			
		||||
				});
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		onStats(stats) {
 | 
			
		||||
			this.stats.push(stats);
 | 
			
		||||
			if (this.stats.length > limit) this.stats.shift();
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		onStatsLog(statsLog) {
 | 
			
		||||
			for (const stats of statsLog.reverse()) {
 | 
			
		||||
				this.onStats(stats);
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		fetchJobs() {
 | 
			
		||||
			this.$root.api('admin/queue/jobs', {
 | 
			
		||||
				domain: this.domain,
 | 
			
		||||
				state: this.state,
 | 
			
		||||
				limit: this.jobsLimit
 | 
			
		||||
			}).then(jobs => {
 | 
			
		||||
				this.jobs = jobs;
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
.wptihjuy
 | 
			
		||||
	> .chart
 | 
			
		||||
		min-height 200px !important
 | 
			
		||||
		margin 0 -8px
 | 
			
		||||
 | 
			
		||||
.xvvuvgsv
 | 
			
		||||
	> b
 | 
			
		||||
		margin-right 16px
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -232,6 +232,8 @@ export default Vue.extend({
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		async silenceUser() {
 | 
			
		||||
			if (!await this.getConfirmed(this.$t('silence-confirm'))) return;
 | 
			
		||||
 | 
			
		||||
			const process = async () => {
 | 
			
		||||
				await this.$root.api('admin/silence-user', { userId: this.user._id });
 | 
			
		||||
				this.$root.dialog({
 | 
			
		||||
@@ -251,6 +253,8 @@ export default Vue.extend({
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		async unsilenceUser() {
 | 
			
		||||
			if (!await this.getConfirmed(this.$t('unsilence-confirm'))) return;
 | 
			
		||||
 | 
			
		||||
			const process = async () => {
 | 
			
		||||
				await this.$root.api('admin/unsilence-user', { userId: this.user._id });
 | 
			
		||||
				this.$root.dialog({
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div class="form">
 | 
			
		||||
	<header>
 | 
			
		||||
		<h1 v-html="$t('share-access', { name: app.name })"></h1>
 | 
			
		||||
		<h1 v-html="$t('share-access', { name })"></h1>
 | 
			
		||||
		<img :src="app.iconUrl"/>
 | 
			
		||||
	</header>
 | 
			
		||||
	<div class="app">
 | 
			
		||||
@@ -42,6 +42,11 @@ export default Vue.extend({
 | 
			
		||||
	i18n: i18n('auth/views/form.vue'),
 | 
			
		||||
	props: ['session'],
 | 
			
		||||
	computed: {
 | 
			
		||||
		name(): string {
 | 
			
		||||
			const el = document.createElement('div');
 | 
			
		||||
			el.textContent = this.app.name
 | 
			
		||||
			return el.innerHTML;
 | 
			
		||||
		},
 | 
			
		||||
		app(): any {
 | 
			
		||||
			return this.session.app;
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -69,7 +69,7 @@ export default Vue.extend({
 | 
			
		||||
				},
 | 
			
		||||
				plotOptions: {
 | 
			
		||||
					bar: {
 | 
			
		||||
						columnWidth: '90%'
 | 
			
		||||
						columnWidth: '80%'
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				grid: {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
		<li v-for="user in users" @click="complete(type, user)" @keydown="onKeydown" tabindex="-1">
 | 
			
		||||
			<img class="avatar" :src="user.avatarUrl" alt=""/>
 | 
			
		||||
			<span class="name">
 | 
			
		||||
				<mk-user-name :user="user"/>
 | 
			
		||||
				<mk-user-name :user="user" :key="user.id"/>
 | 
			
		||||
			</span>
 | 
			
		||||
			<span class="username">@{{ user | acct }}</span>
 | 
			
		||||
		</li>
 | 
			
		||||
@@ -19,7 +19,7 @@
 | 
			
		||||
			<span class="emoji" v-if="emoji.isCustomEmoji"><img :src="emoji.url" :alt="emoji.emoji"/></span>
 | 
			
		||||
			<span class="emoji" v-else-if="!useOsDefaultEmojis"><img :src="emoji.url" :alt="emoji.emoji"/></span>
 | 
			
		||||
			<span class="emoji" v-else>{{ emoji.emoji }}</span>
 | 
			
		||||
			<span class="name" v-html="emoji.name.replace(q, `<b>${q}</b>`)"></span>
 | 
			
		||||
			<span class="name">{{ beforeQ }}<b>{{ q }}</b>{{ afterQ }}</span>
 | 
			
		||||
			<span class="alias" v-if="emoji.aliasOf">({{ emoji.aliasOf }})</span>
 | 
			
		||||
		</li>
 | 
			
		||||
	</ol>
 | 
			
		||||
@@ -30,6 +30,7 @@
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import * as emojilib from 'emojilib';
 | 
			
		||||
import contains from '../../../common/scripts/contains';
 | 
			
		||||
import { twemojiBase } from '../../../../../misc/twemoji-base';
 | 
			
		||||
 | 
			
		||||
type EmojiDef = {
 | 
			
		||||
	emoji: string;
 | 
			
		||||
@@ -54,7 +55,7 @@ const emjdb: EmojiDef[] = lib.map((x: any) => ({
 | 
			
		||||
	emoji: x[1].char,
 | 
			
		||||
	name: x[0],
 | 
			
		||||
	aliasOf: null,
 | 
			
		||||
	url: `https://twemoji.maxcdn.com/2/svg/${char2file(x[1].char)}.svg`
 | 
			
		||||
	url: `${twemojiBase}/2/svg/${char2file(x[1].char)}.svg`
 | 
			
		||||
}));
 | 
			
		||||
 | 
			
		||||
for (const x of lib as any) {
 | 
			
		||||
@@ -64,7 +65,7 @@ for (const x of lib as any) {
 | 
			
		||||
				emoji: x[1].char,
 | 
			
		||||
				name: k,
 | 
			
		||||
				aliasOf: x[0],
 | 
			
		||||
				url: `https://twemoji.maxcdn.com/2/svg/${char2file(x[1].char)}.svg`
 | 
			
		||||
				url: `${twemojiBase}/2/svg/${char2file(x[1].char)}.svg`
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -88,6 +89,14 @@ export default Vue.extend({
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	computed: {
 | 
			
		||||
		beforeQ(): string {
 | 
			
		||||
			return this.emoji.name.split(this.q)[0];
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		afterQ(): string {
 | 
			
		||||
			return this.emoji.name.split(this.q)[1] || '';
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		items(): HTMLCollection {
 | 
			
		||||
			return (this.$refs.suggests as Element).children;
 | 
			
		||||
		},
 | 
			
		||||
 
 | 
			
		||||
@@ -183,9 +183,6 @@ export default Vue.extend({
 | 
			
		||||
	height 100%
 | 
			
		||||
 | 
			
		||||
	&.splash
 | 
			
		||||
		&, *
 | 
			
		||||
			pointer-events none !important
 | 
			
		||||
 | 
			
		||||
		> .main
 | 
			
		||||
			min-width 0
 | 
			
		||||
			width initial
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										187
									
								
								src/client/app/common/views/components/drive-file-thumbnail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								src/client/app/common/views/components/drive-file-thumbnail.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,187 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div class="zdjebgpv" :class="{ detail }" ref="thumbnail" :style="`background-color: ${ background }`">
 | 
			
		||||
	<img
 | 
			
		||||
		:src="file.url"
 | 
			
		||||
		:alt="file.name"
 | 
			
		||||
		:title="file.name"
 | 
			
		||||
		@load="onThumbnailLoaded"
 | 
			
		||||
		v-if="detail && is === 'image'"/>
 | 
			
		||||
	<video
 | 
			
		||||
		:src="file.url"
 | 
			
		||||
		ref="volumectrl"
 | 
			
		||||
		preload="metadata"
 | 
			
		||||
		controls
 | 
			
		||||
		v-else-if="detail && is === 'video'"/>
 | 
			
		||||
	<img :src="file.thumbnailUrl" alt="" @load="onThumbnailLoaded" :style="`object-fit: ${ fit }`" v-else-if="isThumbnailAvailable"/>
 | 
			
		||||
	<fa :icon="faFileImage" class="icon" v-else-if="is === 'image'"/>
 | 
			
		||||
	<fa :icon="faFileVideo" class="icon" v-else-if="is === 'video'"/>
 | 
			
		||||
 | 
			
		||||
	<audio
 | 
			
		||||
		:src="file.url"
 | 
			
		||||
		ref="volumectrl"
 | 
			
		||||
		preload="metadata"
 | 
			
		||||
		controls
 | 
			
		||||
		v-else-if="detail && is === 'audio'"/>
 | 
			
		||||
	<fa :icon="faMusic" class="icon" v-else-if="is === 'audio' || is === 'midi'"/>
 | 
			
		||||
 | 
			
		||||
	<fa :icon="faFileCsv" class="icon" v-else-if="is === 'csv'"/>
 | 
			
		||||
	<fa :icon="faFilePdf" class="icon" v-else-if="is === 'pdf'"/>
 | 
			
		||||
	<fa :icon="faFileAlt" class="icon" v-else-if="is === 'textfile'"/>
 | 
			
		||||
	<fa :icon="faFileArchive" class="icon" v-else-if="is === 'archive'"/>
 | 
			
		||||
	<fa :icon="faFile" class="icon" v-else/>
 | 
			
		||||
 | 
			
		||||
	<fa :icon="faFilm" class="icon-sub" v-if="!detail && isThumbnailAvailable && is === 'video'"/>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import anime from 'animejs';
 | 
			
		||||
import {
 | 
			
		||||
	faFile,
 | 
			
		||||
	faFileAlt,
 | 
			
		||||
	faFileImage,
 | 
			
		||||
	faMusic,
 | 
			
		||||
	faFileVideo,
 | 
			
		||||
	faFileCsv,
 | 
			
		||||
	faFilePdf,
 | 
			
		||||
	faFileArchive,
 | 
			
		||||
	faFilm
 | 
			
		||||
	} from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	props: {
 | 
			
		||||
		file: {
 | 
			
		||||
			type: Object,
 | 
			
		||||
			required: true
 | 
			
		||||
		},
 | 
			
		||||
		fit: {
 | 
			
		||||
			type: String,
 | 
			
		||||
			required: true
 | 
			
		||||
		},
 | 
			
		||||
		detail: {
 | 
			
		||||
			type: Boolean,
 | 
			
		||||
			required: false,
 | 
			
		||||
			default: false
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			isContextmenuShowing: false,
 | 
			
		||||
			isDragging: false,
 | 
			
		||||
 | 
			
		||||
			faFile,
 | 
			
		||||
			faFileAlt,
 | 
			
		||||
			faFileImage,
 | 
			
		||||
			faMusic,
 | 
			
		||||
			faFileVideo,
 | 
			
		||||
			faFileCsv,
 | 
			
		||||
			faFilePdf,
 | 
			
		||||
			faFileArchive,
 | 
			
		||||
			faFilm
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		is(): 'image' | 'video' | 'midi' | 'audio' | 'csv' | 'pdf' | 'textfile' | 'archive' | 'unknown' {
 | 
			
		||||
			if (this.file.type.startsWith('image/')) return 'image';
 | 
			
		||||
			if (this.file.type.startsWith('video/')) return 'video';
 | 
			
		||||
			if (this.file.type === 'audio/midi') return 'midi';
 | 
			
		||||
			if (this.file.type.startsWith('audio/')) return 'audio';
 | 
			
		||||
			if (this.file.type.endsWith('/csv')) return 'csv';
 | 
			
		||||
			if (this.file.type.endsWith('/pdf')) return 'pdf';
 | 
			
		||||
			if (this.file.type.startsWith('text/')) return 'textfile';
 | 
			
		||||
			if ([
 | 
			
		||||
					"application/zip",
 | 
			
		||||
					"application/x-cpio",
 | 
			
		||||
					"application/x-bzip",
 | 
			
		||||
					"application/x-bzip2",
 | 
			
		||||
					"application/java-archive",
 | 
			
		||||
					"application/x-rar-compressed",
 | 
			
		||||
					"application/x-tar",
 | 
			
		||||
					"application/gzip",
 | 
			
		||||
					"application/x-7z-compressed"
 | 
			
		||||
				].some(e => e === this.file.type)) return 'archive';
 | 
			
		||||
			return 'unknown';
 | 
			
		||||
		},
 | 
			
		||||
		isThumbnailAvailable(): boolean {
 | 
			
		||||
			return this.file.thumbnailUrl
 | 
			
		||||
				? this.file.thumbnailUrl.endsWith('?thumbnail')
 | 
			
		||||
					? (this.is === 'image' || this.is === 'video')
 | 
			
		||||
					: true
 | 
			
		||||
				: false;
 | 
			
		||||
		},
 | 
			
		||||
		background(): string {
 | 
			
		||||
			return this.file.properties.avgColor && this.file.properties.avgColor.length == 3
 | 
			
		||||
				? `rgb(${this.file.properties.avgColor.join(',')})`
 | 
			
		||||
				: 'transparent';
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		const audioTag = this.$refs.volumectrl as HTMLAudioElement;
 | 
			
		||||
		if (audioTag) audioTag.volume = this.$store.state.device.mediaVolume;
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		onThumbnailLoaded() {
 | 
			
		||||
			if (this.file.properties.avgColor && this.file.properties.avgColor.length == 3) {
 | 
			
		||||
				anime({
 | 
			
		||||
					targets: this.$refs.thumbnail,
 | 
			
		||||
					backgroundColor: `rgba(${this.file.properties.avgColor.join(',')}, 0)`,
 | 
			
		||||
					duration: 100,
 | 
			
		||||
					easing: 'linear'
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		volumechange() {
 | 
			
		||||
			const audioTag = this.$refs.volumectrl as HTMLAudioElement;
 | 
			
		||||
			this.$store.commit('device/set', { key: 'mediaVolume', value: audioTag.volume });
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
.zdjebgpv
 | 
			
		||||
	display flex
 | 
			
		||||
 | 
			
		||||
	> img,
 | 
			
		||||
	> .icon
 | 
			
		||||
		pointer-events none
 | 
			
		||||
 | 
			
		||||
	> .icon-sub
 | 
			
		||||
		position absolute
 | 
			
		||||
		width 30%
 | 
			
		||||
		height auto
 | 
			
		||||
		margin 0
 | 
			
		||||
		right 4%
 | 
			
		||||
		bottom 4%
 | 
			
		||||
 | 
			
		||||
	> *
 | 
			
		||||
		margin auto
 | 
			
		||||
 | 
			
		||||
	&:not(.detail)
 | 
			
		||||
		> img
 | 
			
		||||
			height 100%
 | 
			
		||||
			width 100%
 | 
			
		||||
			object-fit cover
 | 
			
		||||
 | 
			
		||||
		> .icon
 | 
			
		||||
			height 65%
 | 
			
		||||
			width 65%
 | 
			
		||||
 | 
			
		||||
		> video,
 | 
			
		||||
		> audio
 | 
			
		||||
			width 100%
 | 
			
		||||
 | 
			
		||||
	&.detail
 | 
			
		||||
		> .icon
 | 
			
		||||
			height 100px
 | 
			
		||||
			width 100px
 | 
			
		||||
			margin 16px
 | 
			
		||||
 | 
			
		||||
		> *:not(.icon)
 | 
			
		||||
			max-height 300px
 | 
			
		||||
			max-width 100%
 | 
			
		||||
			height 100%
 | 
			
		||||
			object-fit contain
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
@@ -3,32 +3,31 @@
 | 
			
		||||
	<header>
 | 
			
		||||
		<button v-for="category in categories"
 | 
			
		||||
			:title="category.text"
 | 
			
		||||
			@click="go(category.ref)"
 | 
			
		||||
			@click="go(category)"
 | 
			
		||||
			:class="{ active: category.isActive }"
 | 
			
		||||
		>
 | 
			
		||||
			<fa :icon="category.icon" fixed-width/>
 | 
			
		||||
		</button>
 | 
			
		||||
	</header>
 | 
			
		||||
	<div class="emojis" ref="emojis" @scroll.passive="onScroll">
 | 
			
		||||
		<section v-for="category in categories" :ref="category.ref">
 | 
			
		||||
			<header><fa :icon="category.icon" fixed-width/> {{ category.text }}</header>
 | 
			
		||||
			<div v-if="category.name">
 | 
			
		||||
				<button v-for="emoji in Object.entries(lib).filter(([k, v]) => v.category === category.name)"
 | 
			
		||||
					:title="emoji[0]"
 | 
			
		||||
					@click="chosen(emoji[1].char)"
 | 
			
		||||
				>
 | 
			
		||||
					<mk-emoji :emoji="emoji[1].char"/>
 | 
			
		||||
				</button>
 | 
			
		||||
			</div>
 | 
			
		||||
			<div v-else>
 | 
			
		||||
				<button v-for="emoji in customEmojis"
 | 
			
		||||
					:title="emoji.name"
 | 
			
		||||
					@click="chosen(`:${emoji.name}:`)"
 | 
			
		||||
				>
 | 
			
		||||
					<img :src="emoji.url" :alt="emoji.name"/>
 | 
			
		||||
				</button>
 | 
			
		||||
			</div>
 | 
			
		||||
		</section>
 | 
			
		||||
	<div class="emojis">
 | 
			
		||||
		<header><fa :icon="categories.find(x => x.isActive).icon" fixed-width/> {{ categories.find(x => x.isActive).text }}</header>
 | 
			
		||||
		<div v-if="categories.find(x => x.isActive).name">
 | 
			
		||||
			<button v-for="emoji in Object.entries(lib).filter(([k, v]) => v.category === categories.find(x => x.isActive).name)"
 | 
			
		||||
				:title="emoji[0]"
 | 
			
		||||
				@click="chosen(emoji[1].char)"
 | 
			
		||||
				:key="emoji[0]"
 | 
			
		||||
			>
 | 
			
		||||
				<mk-emoji :emoji="emoji[1].char"/>
 | 
			
		||||
			</button>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div v-else>
 | 
			
		||||
			<button v-for="emoji in customEmojis"
 | 
			
		||||
				:title="emoji.name"
 | 
			
		||||
				@click="chosen(`:${emoji.name}:`)"
 | 
			
		||||
			>
 | 
			
		||||
				<img :src="emoji.url" :alt="emoji.name"/>
 | 
			
		||||
			</button>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
@@ -48,55 +47,46 @@ export default Vue.extend({
 | 
			
		||||
			lib,
 | 
			
		||||
			customEmojis: [],
 | 
			
		||||
			categories: [{
 | 
			
		||||
				ref: 'customEmojiSection',
 | 
			
		||||
				text: this.$t('custom-emoji'),
 | 
			
		||||
				icon: faAsterisk,
 | 
			
		||||
				isActive: true
 | 
			
		||||
			}, {
 | 
			
		||||
				name: 'people',
 | 
			
		||||
				ref: 'peopleSection',
 | 
			
		||||
				text: this.$t('people'),
 | 
			
		||||
				icon: ['far', 'laugh'],
 | 
			
		||||
				isActive: false
 | 
			
		||||
			}, {
 | 
			
		||||
				name: 'animals_and_nature',
 | 
			
		||||
				ref: 'animalsAndNatureSection',
 | 
			
		||||
				text: this.$t('animals-and-nature'),
 | 
			
		||||
				icon: faLeaf,
 | 
			
		||||
				isActive: false
 | 
			
		||||
			}, {
 | 
			
		||||
				name: 'food_and_drink',
 | 
			
		||||
				ref: 'foodAndDrinkSection',
 | 
			
		||||
				text: this.$t('food-and-drink'),
 | 
			
		||||
				icon: faUtensils,
 | 
			
		||||
				isActive: false
 | 
			
		||||
			}, {
 | 
			
		||||
				name: 'activity',
 | 
			
		||||
				ref: 'activitySection',
 | 
			
		||||
				text: this.$t('activity'),
 | 
			
		||||
				icon: faFutbol,
 | 
			
		||||
				isActive: false
 | 
			
		||||
			}, {
 | 
			
		||||
				name: 'travel_and_places',
 | 
			
		||||
				ref: 'travelAndPlacesSection',
 | 
			
		||||
				text: this.$t('travel-and-places'),
 | 
			
		||||
				icon: faCity,
 | 
			
		||||
				isActive: false
 | 
			
		||||
			}, {
 | 
			
		||||
				name: 'objects',
 | 
			
		||||
				ref: 'objectsSection',
 | 
			
		||||
				text: this.$t('objects'),
 | 
			
		||||
				icon: faDice,
 | 
			
		||||
				isActive: false
 | 
			
		||||
			}, {
 | 
			
		||||
				name: 'symbols',
 | 
			
		||||
				ref: 'symbolsSection',
 | 
			
		||||
				text: this.$t('symbols'),
 | 
			
		||||
				icon: faHeart,
 | 
			
		||||
				isActive: false
 | 
			
		||||
			}, {
 | 
			
		||||
				name: 'flags',
 | 
			
		||||
				ref: 'flagsSection',
 | 
			
		||||
				text: this.$t('flags'),
 | 
			
		||||
				icon: faFlag,
 | 
			
		||||
				isActive: false
 | 
			
		||||
@@ -109,15 +99,9 @@ export default Vue.extend({
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	methods: {
 | 
			
		||||
		go(ref) {
 | 
			
		||||
			this.$refs.emojis.scrollTop = this.$refs[ref][0].offsetTop;
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		onScroll(e) {
 | 
			
		||||
			for (const x of this.categories) {
 | 
			
		||||
				const top = e.target.scrollTop;
 | 
			
		||||
				const el = this.$refs[x.ref][0];
 | 
			
		||||
				x.isActive = el.offsetTop <= top && el.offsetTop + el.offsetHeight > top;
 | 
			
		||||
		go(category) {
 | 
			
		||||
			for (const c of this.categories) {
 | 
			
		||||
				c.isActive = c.name === category.name;
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
@@ -156,47 +140,46 @@ export default Vue.extend({
 | 
			
		||||
		overflow-y auto
 | 
			
		||||
		overflow-x hidden
 | 
			
		||||
 | 
			
		||||
		> section
 | 
			
		||||
			> header
 | 
			
		||||
				position sticky
 | 
			
		||||
				top 0
 | 
			
		||||
				left 0
 | 
			
		||||
				z-index 1
 | 
			
		||||
				padding 8px
 | 
			
		||||
				background var(--faceHeader)
 | 
			
		||||
				color var(--text)
 | 
			
		||||
				font-size 12px
 | 
			
		||||
		> header
 | 
			
		||||
			position sticky
 | 
			
		||||
			top 0
 | 
			
		||||
			left 0
 | 
			
		||||
			z-index 1
 | 
			
		||||
			padding 8px
 | 
			
		||||
			background var(--faceHeader)
 | 
			
		||||
			color var(--text)
 | 
			
		||||
			font-size 12px
 | 
			
		||||
 | 
			
		||||
			> div
 | 
			
		||||
				display grid
 | 
			
		||||
				grid-template-columns 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr
 | 
			
		||||
				gap 4px
 | 
			
		||||
				padding 8px
 | 
			
		||||
		> div
 | 
			
		||||
			display grid
 | 
			
		||||
			grid-template-columns 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr
 | 
			
		||||
			gap 4px
 | 
			
		||||
			padding 8px
 | 
			
		||||
 | 
			
		||||
				> button
 | 
			
		||||
					padding 0
 | 
			
		||||
					width 100%
 | 
			
		||||
			> button
 | 
			
		||||
				padding 0
 | 
			
		||||
				width 100%
 | 
			
		||||
 | 
			
		||||
					&:before
 | 
			
		||||
						content ''
 | 
			
		||||
						display block
 | 
			
		||||
						width 1px
 | 
			
		||||
						height 0
 | 
			
		||||
						padding-bottom 100%
 | 
			
		||||
 | 
			
		||||
					&:hover
 | 
			
		||||
						> *
 | 
			
		||||
							transform scale(1.2)
 | 
			
		||||
							transition transform 0s
 | 
			
		||||
				&:before
 | 
			
		||||
					content ''
 | 
			
		||||
					display block
 | 
			
		||||
					width 1px
 | 
			
		||||
					height 0
 | 
			
		||||
					padding-bottom 100%
 | 
			
		||||
 | 
			
		||||
				&:hover
 | 
			
		||||
					> *
 | 
			
		||||
						position absolute
 | 
			
		||||
						top 0
 | 
			
		||||
						left 0
 | 
			
		||||
						width 100%
 | 
			
		||||
						height 100%
 | 
			
		||||
						font-size 28px
 | 
			
		||||
						transition transform 0.2s ease
 | 
			
		||||
						pointer-events none
 | 
			
		||||
						transform scale(1.2)
 | 
			
		||||
						transition transform 0s
 | 
			
		||||
 | 
			
		||||
				> *
 | 
			
		||||
					position absolute
 | 
			
		||||
					top 0
 | 
			
		||||
					left 0
 | 
			
		||||
					width 100%
 | 
			
		||||
					height 100%
 | 
			
		||||
					font-size 28px
 | 
			
		||||
					transition transform 0.2s ease
 | 
			
		||||
					pointer-events none
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ import Vue from 'vue';
 | 
			
		||||
// スクリプトサイズがデカい
 | 
			
		||||
//import { lib } from 'emojilib';
 | 
			
		||||
import { getStaticImageUrl } from '../../../common/scripts/get-static-image-url';
 | 
			
		||||
import { twemojiBase } from '../../../../../misc/twemoji-base';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	props: {
 | 
			
		||||
@@ -29,7 +30,11 @@ export default Vue.extend({
 | 
			
		||||
		customEmojis: {
 | 
			
		||||
			required: false,
 | 
			
		||||
			default: () => []
 | 
			
		||||
		}
 | 
			
		||||
		},
 | 
			
		||||
		isReaction: {
 | 
			
		||||
			type: Boolean,
 | 
			
		||||
			default: false
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	data() {
 | 
			
		||||
@@ -46,7 +51,7 @@ export default Vue.extend({
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		useOsDefaultEmojis(): boolean {
 | 
			
		||||
			return this.$store.state.device.useOsDefaultEmojis;
 | 
			
		||||
			return this.$store.state.device.useOsDefaultEmojis && !this.isReaction;
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
@@ -73,7 +78,7 @@ export default Vue.extend({
 | 
			
		||||
			if (!codes.includes('200d')) codes = codes.filter(x => x != 'fe0f');
 | 
			
		||||
			codes = codes.filter(x => x && x.length);
 | 
			
		||||
 | 
			
		||||
			this.url = `https://twemoji.maxcdn.com/2/svg/${codes.join('-')}.svg`;
 | 
			
		||||
			this.url = `${twemojiBase}/2/svg/${codes.join('-')}.svg`;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
<a class="a" href="https://github.com/syuilo/misskey" target="_blank" title="View source on GitHub">
 | 
			
		||||
<a class="a" :href="repositoryUrl" rel="noopener" target="_blank" title="View source on GitHub">
 | 
			
		||||
	<svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="aria-hidden">
 | 
			
		||||
		<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
 | 
			
		||||
		<path class="octo-arm" d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor"></path>
 | 
			
		||||
@@ -8,9 +8,19 @@
 | 
			
		||||
</a>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue'
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			repositoryUrl: 'https://github.com/syuilo/misskey'
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.a
 | 
			
		||||
	display block
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,17 +5,17 @@
 | 
			
		||||
 | 
			
		||||
	<div style="overflow: hidden; line-height: 28px;">
 | 
			
		||||
		<p class="turn" v-if="!iAmPlayer && !game.isEnded">
 | 
			
		||||
			<mfm :text="$t('@.reversi.turn-of', { name: $options.filters.userName(turnUser) })" :should-break="false" :plain-text="true" :custom-emojis="turnUser.emojis"/>
 | 
			
		||||
			<mfm :key="'turn:' + $options.filters.userName(turnUser)" :text="$t('@.reversi.turn-of', { name: $options.filters.userName(turnUser) })" :should-break="false" :plain-text="true" :custom-emojis="turnUser.emojis"/>
 | 
			
		||||
			<mk-ellipsis/>
 | 
			
		||||
		</p>
 | 
			
		||||
		<p class="turn" v-if="logPos != logs.length">
 | 
			
		||||
			<mfm :text="$t('@.reversi.past-turn-of', { name: $options.filters.userName(turnUser) })" :should-break="false" :plain-text="true" :custom-emojis="turnUser.emojis"/>
 | 
			
		||||
			<mfm :key="'past-turn-of:' + $options.filters.userName(turnUser)" :text="$t('@.reversi.past-turn-of', { name: $options.filters.userName(turnUser) })" :should-break="false" :plain-text="true" :custom-emojis="turnUser.emojis"/>
 | 
			
		||||
		</p>
 | 
			
		||||
		<p class="turn1" v-if="iAmPlayer && !game.isEnded && !isMyTurn">{{ $t('@.reversi.opponent-turn') }}<mk-ellipsis/></p>
 | 
			
		||||
		<p class="turn2" v-if="iAmPlayer && !game.isEnded && isMyTurn" v-animate-css="{ classes: 'tada', iteration: 'infinite' }">{{ $t('@.reversi.my-turn') }}</p>
 | 
			
		||||
		<p class="result" v-if="game.isEnded && logPos == logs.length">
 | 
			
		||||
			<template v-if="game.winner">
 | 
			
		||||
				<mfm :text="$t('@.reversi.won', { name: $options.filters.userName(game.winner) })" :should-break="false" :plain-text="true" :custom-emojis="game.winner.emojis"/>
 | 
			
		||||
				<mfm :key="'won'" :text="$t('@.reversi.won', { name: $options.filters.userName(game.winner) })" :should-break="false" :plain-text="true" :custom-emojis="game.winner.emojis"/>
 | 
			
		||||
				<span v-if="game.surrendered != null"> ({{ $t('surrendered') }})</span>
 | 
			
		||||
			</template>
 | 
			
		||||
			<template v-else>{{ $t('@.reversi.drawn') }}</template>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
<a class="zxrjzpcj" :href="url" :class="service" target="_blank">
 | 
			
		||||
<a class="zxrjzpcj" :href="url" :class="service" rel="noopener" target="_blank">
 | 
			
		||||
	<fa :icon="icon" size="lg" fixed-width /><span>{{ text }}</span>
 | 
			
		||||
</a>
 | 
			
		||||
</template>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div class="onchrpzrvnoruiaenfcqvccjfuupzzwv" :class="{ isMobile: $root.isMobile }">
 | 
			
		||||
	<div class="backdrop" ref="backdrop" @click="close"></div>
 | 
			
		||||
	<div class="popover" :class="{ hukidasi }" ref="popover">
 | 
			
		||||
	<div class="popover" :class="{ bubble }" ref="popover">
 | 
			
		||||
		<template v-for="item, i in items">
 | 
			
		||||
			<div v-if="item === null"></div>
 | 
			
		||||
			<button v-if="item" @click="clicked(item.action)" :tabindex="i">
 | 
			
		||||
@@ -28,7 +28,7 @@ export default Vue.extend({
 | 
			
		||||
	},
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			hukidasi: !this.$root.isMobile
 | 
			
		||||
			bubble: !this.$root.isMobile
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
@@ -56,12 +56,12 @@ export default Vue.extend({
 | 
			
		||||
 | 
			
		||||
			if (left + width - window.pageXOffset > window.innerWidth) {
 | 
			
		||||
				left = window.innerWidth - width + window.pageXOffset;
 | 
			
		||||
				this.hukidasi = false;
 | 
			
		||||
				this.bubble = false;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (top + height - window.pageYOffset > window.innerHeight) {
 | 
			
		||||
				top = window.innerHeight - height + window.pageYOffset;
 | 
			
		||||
				this.hukidasi = false;
 | 
			
		||||
				this.bubble = false;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (top < 0) {
 | 
			
		||||
@@ -150,7 +150,7 @@ export default Vue.extend({
 | 
			
		||||
 | 
			
		||||
		$balloon-size = 16px
 | 
			
		||||
 | 
			
		||||
		&.hukidasi
 | 
			
		||||
		&.bubble
 | 
			
		||||
			margin-top $balloon-size
 | 
			
		||||
			transform-origin center -($balloon-size)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
			<div class="content" v-if="!message.isDeleted">
 | 
			
		||||
				<mfm class="text" v-if="message.text" ref="text" :text="message.text" :i="$store.state.i"/>
 | 
			
		||||
				<div class="file" v-if="message.file">
 | 
			
		||||
					<a :href="message.file.url" target="_blank" :title="message.file.name">
 | 
			
		||||
					<a :href="message.file.url" rel="noopener" target="_blank" :title="message.file.name">
 | 
			
		||||
						<img v-if="message.file.type.split('/')[0] == 'image'" :src="message.file.url" :alt="message.file.name"
 | 
			
		||||
							:style="{ backgroundColor: message.file.properties.avgColor && message.file.properties.avgColor.length == 3 ? `rgb(${message.file.properties.avgColor.join(',')})` : 'transparent' }"/>
 | 
			
		||||
						<p v-else>{{ message.file.name }}</p>
 | 
			
		||||
 
 | 
			
		||||
@@ -270,17 +270,13 @@ export default Vue.extend({
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
.mk-messaging-room
 | 
			
		||||
	display flex
 | 
			
		||||
	flex 1
 | 
			
		||||
	flex-direction column
 | 
			
		||||
	height 100%
 | 
			
		||||
	background var(--messagingRoomBg)
 | 
			
		||||
 | 
			
		||||
	> .body
 | 
			
		||||
		width 100%
 | 
			
		||||
		max-width 600px
 | 
			
		||||
		margin 0 auto
 | 
			
		||||
		flex 1
 | 
			
		||||
		min-height calc(100% - 103px)
 | 
			
		||||
 | 
			
		||||
		> .init,
 | 
			
		||||
		> .empty
 | 
			
		||||
 
 | 
			
		||||
@@ -174,6 +174,7 @@ export default Vue.component('misskey-flavored-markdown', {
 | 
			
		||||
						key: Math.random(),
 | 
			
		||||
						props: {
 | 
			
		||||
							url: token.node.props.url,
 | 
			
		||||
							rel: 'nofollow noopener',
 | 
			
		||||
							target: '_blank'
 | 
			
		||||
						},
 | 
			
		||||
						attrs: {
 | 
			
		||||
@@ -187,6 +188,7 @@ export default Vue.component('misskey-flavored-markdown', {
 | 
			
		||||
						attrs: {
 | 
			
		||||
							class: 'link',
 | 
			
		||||
							href: token.node.props.url,
 | 
			
		||||
							rel: 'nofollow noopener',
 | 
			
		||||
							target: '_blank',
 | 
			
		||||
							title: token.node.props.url,
 | 
			
		||||
							style: 'color:var(--mfmLink);'
 | 
			
		||||
 
 | 
			
		||||
@@ -2,9 +2,9 @@
 | 
			
		||||
<span class="mk-nav">
 | 
			
		||||
	<a :href="aboutUrl">{{ $t('about') }}</a>
 | 
			
		||||
	<i>・</i>
 | 
			
		||||
	<a :href="repositoryUrl">{{ $t('repository') }}</a>
 | 
			
		||||
	<a :href="repositoryUrl" rel="noopener" target="_blank">{{ $t('repository') }}</a>
 | 
			
		||||
	<i>・</i>
 | 
			
		||||
	<a :href="feedbackUrl" target="_blank">{{ $t('feedback') }}</a>
 | 
			
		||||
	<a :href="feedbackUrl" rel="noopener" target="_blank">{{ $t('feedback') }}</a>
 | 
			
		||||
	<i>・</i>
 | 
			
		||||
	<a href="/dev">{{ $t('develop') }}</a>
 | 
			
		||||
</span>
 | 
			
		||||
@@ -23,12 +23,6 @@ export default Vue.extend({
 | 
			
		||||
			repositoryUrl: 'https://github.com/syuilo/misskey',
 | 
			
		||||
			feedbackUrl: 'https://github.com/syuilo/misskey/issues/new'
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	created() {
 | 
			
		||||
		this.$root.getMeta().then(meta => {
 | 
			
		||||
			if (meta.maintainer.repository_url) this.repositoryUrl = meta.maintainer.repository_url;
 | 
			
		||||
			if (meta.maintainer.feedback_url) this.feedbackUrl = meta.maintainer.feedback_url;
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -12,21 +12,54 @@
 | 
			
		||||
		</li>
 | 
			
		||||
	</ul>
 | 
			
		||||
	<button class="add" v-if="choices.length < 10" @click="add">{{ $t('add') }}</button>
 | 
			
		||||
	<button class="add" v-else disabled>{{ $t('no-more') }}</button>
 | 
			
		||||
	<button class="destroy" @click="destroy" :title="$t('destroy')">
 | 
			
		||||
		<fa icon="times"/>
 | 
			
		||||
	</button>
 | 
			
		||||
	<section>
 | 
			
		||||
		<ui-switch v-model="multiple">{{ $t('multiple') }}</ui-switch>
 | 
			
		||||
		<div>
 | 
			
		||||
			<ui-select v-model="expiration">
 | 
			
		||||
				<template #label>{{ $t('expiration') }}</template>
 | 
			
		||||
				<option value="infinite">{{ $t('infinite') }}</option>
 | 
			
		||||
				<option value="at">{{ $t('at') }}</option>
 | 
			
		||||
				<option value="after">{{ $t('after') }}</option>
 | 
			
		||||
			</ui-select>
 | 
			
		||||
			<section v-if="expiration === 'at'">
 | 
			
		||||
				<ui-input v-model="atDate" type="date">{{ $t('deadline-date') }}</ui-input>
 | 
			
		||||
				<ui-input v-model="atTime" type="time">{{ $t('deadline-time') }}</ui-input>
 | 
			
		||||
			</section>
 | 
			
		||||
			<section v-if="expiration === 'after'">
 | 
			
		||||
				<ui-input v-model="after" type="number">{{ $t('interval') }}</ui-input>
 | 
			
		||||
				<ui-select v-model="unit">
 | 
			
		||||
					<template #label>{{ $t('unit') }}</template>
 | 
			
		||||
					<option value="second">{{ $t('second') }}</option>
 | 
			
		||||
					<option value="minute">{{ $t('minute') }}</option>
 | 
			
		||||
					<option value="hour">{{ $t('hour') }}</option>
 | 
			
		||||
					<option value="day">{{ $t('day') }}</option>
 | 
			
		||||
				</ui-select>
 | 
			
		||||
			</section>
 | 
			
		||||
		</div>
 | 
			
		||||
	</section>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import * as moment from 'moment';
 | 
			
		||||
import i18n from '../../../i18n';
 | 
			
		||||
import { erase } from '../../../../../prelude/array';
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	i18n: i18n('common/views/components/poll-editor.vue'),
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			choices: ['', '']
 | 
			
		||||
			choices: ['', ''],
 | 
			
		||||
			multiple: false,
 | 
			
		||||
			expiration: 'infinite',
 | 
			
		||||
			atDate: moment().add(1, 'day').toISOString().split('T')[0],
 | 
			
		||||
			atTime: '00:00',
 | 
			
		||||
			after: 0,
 | 
			
		||||
			unit: 'second'
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	watch: {
 | 
			
		||||
@@ -55,15 +88,46 @@ export default Vue.extend({
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		get() {
 | 
			
		||||
			const at = () => {
 | 
			
		||||
				const [date] = moment(this.atDate).toISOString().split('T');
 | 
			
		||||
				const [hour, minute] = this.atTime.split(':');
 | 
			
		||||
				return moment(`${date}T${hour}:${minute}Z`).valueOf();
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			const after = () => {
 | 
			
		||||
				let base = parseInt(this.after);
 | 
			
		||||
				switch (this.unit) {
 | 
			
		||||
					case 'day': base *= 24;
 | 
			
		||||
					case 'hour': base *= 60;
 | 
			
		||||
					case 'minute': base *= 60;
 | 
			
		||||
					case 'second': return base *= 1000;
 | 
			
		||||
					default: return null;
 | 
			
		||||
				}
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			return {
 | 
			
		||||
				choices: erase('', this.choices)
 | 
			
		||||
			}
 | 
			
		||||
				choices: erase('', this.choices),
 | 
			
		||||
				multiple: this.multiple,
 | 
			
		||||
				...(
 | 
			
		||||
					this.expiration === 'at' ? { expiresAt: at() } :
 | 
			
		||||
					this.expiration === 'after' ? { expiredAfter: after() } : {})
 | 
			
		||||
			};
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		set(data) {
 | 
			
		||||
			if (data.choices.length == 0) return;
 | 
			
		||||
			this.choices = data.choices;
 | 
			
		||||
			if (data.choices.length == 1) this.choices = this.choices.concat('');
 | 
			
		||||
			this.multiple = data.multiple;
 | 
			
		||||
			if (data.expiresAt) {
 | 
			
		||||
				this.expiration = 'at';
 | 
			
		||||
				this.atDate = this.atTime = data.expiresAt;
 | 
			
		||||
			} else if (typeof data.expiredAfter === 'number') {
 | 
			
		||||
				this.expiration = 'after';
 | 
			
		||||
				this.after = data.expiredAfter;
 | 
			
		||||
			} else {
 | 
			
		||||
				this.expiration = 'infinite';
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
@@ -128,6 +192,7 @@ export default Vue.extend({
 | 
			
		||||
		margin 8px 0 0 0
 | 
			
		||||
		vertical-align top
 | 
			
		||||
		color var(--primary)
 | 
			
		||||
		z-index 1
 | 
			
		||||
 | 
			
		||||
	> .destroy
 | 
			
		||||
		position absolute
 | 
			
		||||
@@ -142,4 +207,23 @@ export default Vue.extend({
 | 
			
		||||
		&:active
 | 
			
		||||
			color var(--primaryDarken30)
 | 
			
		||||
 | 
			
		||||
	> section
 | 
			
		||||
		margin 16px 0 -16px 0
 | 
			
		||||
 | 
			
		||||
		> div
 | 
			
		||||
			margin 0 8px
 | 
			
		||||
 | 
			
		||||
			&:last-child
 | 
			
		||||
				flex 1 0 auto
 | 
			
		||||
 | 
			
		||||
				> section
 | 
			
		||||
					align-items center
 | 
			
		||||
					display flex
 | 
			
		||||
					margin -32px 0 0
 | 
			
		||||
 | 
			
		||||
					> :first-child
 | 
			
		||||
						margin-right 16px
 | 
			
		||||
 | 
			
		||||
					> .ui-input
 | 
			
		||||
						flex 1 0 auto
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div class="mk-poll" :data-is-voted="isVoted">
 | 
			
		||||
<div class="mk-poll" :data-done="closed || isVoted">
 | 
			
		||||
	<ul>
 | 
			
		||||
		<li v-for="choice in poll.choices" :key="choice.id" @click="vote(choice.id)" :class="{ voted: choice.voted }" :title="!isVoted ? $t('vote-to').replace('{}', choice.text) : ''">
 | 
			
		||||
			<div class="backdrop" :style="{ 'width': (showResult ? (choice.votes / total * 100) : 0) + '%' }"></div>
 | 
			
		||||
		<li v-for="choice in poll.choices" :key="choice.id" @click="vote(choice.id)" :class="{ voted: choice.voted }" :title="!closed && !isVoted ? $t('vote-to').replace('{}', choice.text) : ''">
 | 
			
		||||
			<div class="backdrop" :style="{ 'width': `${showResult ? (choice.votes / total * 100) : 0}%` }"></div>
 | 
			
		||||
			<span>
 | 
			
		||||
				<template v-if="choice.isVoted"><fa icon="check"/></template>
 | 
			
		||||
				<mfm :text="choice.text" :should-break="false" :plain-text="true" :custom-emojis="note.emojis"/>
 | 
			
		||||
@@ -10,11 +10,13 @@
 | 
			
		||||
			</span>
 | 
			
		||||
		</li>
 | 
			
		||||
	</ul>
 | 
			
		||||
	<p v-if="total > 0">
 | 
			
		||||
		<span>{{ $t('total-users').replace('{}', total) }}</span>
 | 
			
		||||
		<span>・</span>
 | 
			
		||||
		<a v-if="!isVoted" @click="toggleShowResult">{{ showResult ? $t('vote') : $t('show-result') }}</a>
 | 
			
		||||
	<p>
 | 
			
		||||
		<span>{{ $t('total-votes').replace('{}', total) }}</span>
 | 
			
		||||
		<span> · </span>
 | 
			
		||||
		<a v-if="!closed && !isVoted" @click="toggleShowResult">{{ showResult ? $t('vote') : $t('show-result') }}</a>
 | 
			
		||||
		<span v-if="isVoted">{{ $t('voted') }}</span>
 | 
			
		||||
		<span v-else-if="closed">{{ $t('closed') }}</span>
 | 
			
		||||
		<span v-if="remaining > 0"> · {{ timer }}</span>
 | 
			
		||||
	</p>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
@@ -28,6 +30,7 @@ export default Vue.extend({
 | 
			
		||||
	props: ['note'],
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			remaining: -1,
 | 
			
		||||
			showResult: false
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
@@ -38,19 +41,43 @@ export default Vue.extend({
 | 
			
		||||
		total(): number {
 | 
			
		||||
			return sum(this.poll.choices.map(x => x.votes));
 | 
			
		||||
		},
 | 
			
		||||
		closed(): boolean {
 | 
			
		||||
			return !this.remaining;
 | 
			
		||||
		},
 | 
			
		||||
		timer(): string {
 | 
			
		||||
			return this.$t(
 | 
			
		||||
				this.remaining > 86400 ? 'remaining-days' :
 | 
			
		||||
				this.remaining > 3600 ? 'remaining-hours' :
 | 
			
		||||
				this.remaining > 60 ? 'remaining-minutes' : 'remaining-seconds')
 | 
			
		||||
				.replace('{s}', Math.floor(this.remaining % 60))
 | 
			
		||||
				.replace('{m}', Math.floor(this.remaining / 60) % 60)
 | 
			
		||||
				.replace('{h}', Math.floor(this.remaining / 3600) % 24)
 | 
			
		||||
				.replace('{d}', Math.floor(this.remaining / 86400));
 | 
			
		||||
		},
 | 
			
		||||
		isVoted(): boolean {
 | 
			
		||||
			return this.poll.choices.some(c => c.isVoted);
 | 
			
		||||
			return !this.poll.multiple && this.poll.choices.some(c => c.isVoted);
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	created() {
 | 
			
		||||
		this.showResult = this.isVoted;
 | 
			
		||||
 | 
			
		||||
		if (this.note.poll.expiresAt) {
 | 
			
		||||
			const update = () => {
 | 
			
		||||
				if (this.remaining = Math.floor(Math.max(new Date(this.note.poll.expiresAt).getTime() - Date.now(), 0) / 1000))
 | 
			
		||||
					requestAnimationFrame(update);
 | 
			
		||||
				else
 | 
			
		||||
					this.showResult = true;
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			update();
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		toggleShowResult() {
 | 
			
		||||
			this.showResult = !this.showResult;
 | 
			
		||||
		},
 | 
			
		||||
		vote(id) {
 | 
			
		||||
			if (this.poll.choices.some(c => c.isVoted)) return;
 | 
			
		||||
			if (this.closed || !this.poll.multiple && this.poll.choices.some(c => c.isVoted)) return;
 | 
			
		||||
			this.$root.api('notes/polls/vote', {
 | 
			
		||||
				noteId: this.note.id,
 | 
			
		||||
				choice: id
 | 
			
		||||
@@ -61,7 +88,7 @@ export default Vue.extend({
 | 
			
		||||
						Vue.set(c, 'isVoted', true);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				this.showResult = true;
 | 
			
		||||
				if (!this.showResult) this.showResult = !this.poll.multiple;
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -114,7 +141,7 @@ export default Vue.extend({
 | 
			
		||||
		a
 | 
			
		||||
			color inherit
 | 
			
		||||
 | 
			
		||||
	&[data-is-voted]
 | 
			
		||||
	&[data-done]
 | 
			
		||||
		> ul > li
 | 
			
		||||
			cursor default
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										140
									
								
								src/client/app/common/views/components/post-form-attaches.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								src/client/app/common/views/components/post-form-attaches.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,140 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div class="skeikyzd" v-show="files.length != 0">
 | 
			
		||||
	<x-draggable class="files" :list="files" :options="{ animation: 150 }">
 | 
			
		||||
		<div v-for="file in files" :key="file.id" @click="showFileMenu(file, $event)" @contextmenu.prevent="showFileMenu(file, $event)">
 | 
			
		||||
			<x-file-thumbnail :data-id="file.id" class="thumbnail" :file="file" fit="cover"/>
 | 
			
		||||
			<img class="remove" @click.stop="detachMedia(file.id)" src="/assets/desktop/remove.png" :title="$t('attach-cancel')" alt=""/>
 | 
			
		||||
			<div class="sensitive" v-if="file.isSensitive">
 | 
			
		||||
				<fa class="icon" :icon="faExclamationTriangle"/>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
	</x-draggable>
 | 
			
		||||
	<p class="remain">{{ 4 - files.length }}/4</p>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import i18n from '../../../i18n';
 | 
			
		||||
import * as XDraggable from 'vuedraggable';
 | 
			
		||||
import XMenu from '../../../common/views/components/menu.vue';
 | 
			
		||||
import { faTimesCircle, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
 | 
			
		||||
import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import XFileThumbnail from './drive-file-thumbnail.vue'
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	i18n: i18n('common/views/components/post-form-attaches.vue'),
 | 
			
		||||
 | 
			
		||||
	components: {
 | 
			
		||||
		XDraggable,
 | 
			
		||||
		XFileThumbnail
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	props: {
 | 
			
		||||
		files: {
 | 
			
		||||
			type: Object,
 | 
			
		||||
			required: true
 | 
			
		||||
		},
 | 
			
		||||
		detachMediaFn: {
 | 
			
		||||
			type: Object,
 | 
			
		||||
			required: false
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			faExclamationTriangle
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	methods: {
 | 
			
		||||
		detachMedia(id) {
 | 
			
		||||
			if (this.detachMediaFn) this.detachMediaFn(id)
 | 
			
		||||
			else if (this.$parent.detachMedia) this.$parent.detachMedia(id)
 | 
			
		||||
		},
 | 
			
		||||
		toggleSensitive(file) {
 | 
			
		||||
			this.$root.api('drive/files/update', {
 | 
			
		||||
				fileId: file.id,
 | 
			
		||||
				isSensitive: !file.isSensitive
 | 
			
		||||
			}).then(() => {
 | 
			
		||||
				file.isSensitive = !file.isSensitive;
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		showFileMenu(file, ev: MouseEvent) {
 | 
			
		||||
			this.$root.new(XMenu, {
 | 
			
		||||
				items: [{
 | 
			
		||||
					type: 'item',
 | 
			
		||||
					text: file.isSensitive ? this.$t('unmark-as-sensitive') : this.$t('mark-as-sensitive'),
 | 
			
		||||
					icon: file.isSensitive ? faEyeSlash : faEye,
 | 
			
		||||
					action: () => { this.toggleSensitive(file) }
 | 
			
		||||
				}, {
 | 
			
		||||
					type: 'item',
 | 
			
		||||
					text: this.$t('attach-cancel'),
 | 
			
		||||
					icon: faTimesCircle,
 | 
			
		||||
					action: () => { this.detachMedia(file.id) }
 | 
			
		||||
				}],
 | 
			
		||||
				source: ev.currentTarget || ev.target
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
.skeikyzd
 | 
			
		||||
	padding 4px
 | 
			
		||||
 | 
			
		||||
	> .files
 | 
			
		||||
		display flex
 | 
			
		||||
		flex-wrap wrap
 | 
			
		||||
 | 
			
		||||
		> div
 | 
			
		||||
			width 64px
 | 
			
		||||
			height 64px
 | 
			
		||||
			margin 4px
 | 
			
		||||
			cursor move
 | 
			
		||||
 | 
			
		||||
			&:hover > .remove
 | 
			
		||||
				display block
 | 
			
		||||
 | 
			
		||||
			> .thumbnail
 | 
			
		||||
				width 100%
 | 
			
		||||
				height 100%
 | 
			
		||||
				z-index 1
 | 
			
		||||
				color var(--text)
 | 
			
		||||
				background-color: rgba(128, 128, 128, 0.3)
 | 
			
		||||
 | 
			
		||||
			> .remove
 | 
			
		||||
				display none
 | 
			
		||||
				position absolute
 | 
			
		||||
				top -6px
 | 
			
		||||
				right -6px
 | 
			
		||||
				width 16px
 | 
			
		||||
				height 16px
 | 
			
		||||
				cursor pointer
 | 
			
		||||
				z-index 1000
 | 
			
		||||
 | 
			
		||||
			> .sensitive
 | 
			
		||||
				display flex
 | 
			
		||||
				position absolute
 | 
			
		||||
				width 64px
 | 
			
		||||
				height 64px
 | 
			
		||||
				top 0
 | 
			
		||||
				left 0
 | 
			
		||||
				z-index 2
 | 
			
		||||
				background rgba(17, 17, 17, .7)
 | 
			
		||||
				color #fff
 | 
			
		||||
 | 
			
		||||
				> .icon
 | 
			
		||||
					margin auto
 | 
			
		||||
 | 
			
		||||
	> .remain
 | 
			
		||||
		display block
 | 
			
		||||
		position absolute
 | 
			
		||||
		top 8px
 | 
			
		||||
		right 8px
 | 
			
		||||
		margin 0
 | 
			
		||||
		padding 0
 | 
			
		||||
		color var(--primaryAlpha04)
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
@@ -1,19 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
<span class="mk-reaction-icon">
 | 
			
		||||
	<img v-if="reaction == 'like'" src="https://twemoji.maxcdn.com/2/svg/1f44d.svg" :alt="$t('@.reactions.like')">
 | 
			
		||||
	<img v-if="reaction == 'love'" src="https://twemoji.maxcdn.com/2/svg/2764.svg" :alt="$t('@.reactions.love')">
 | 
			
		||||
	<img v-if="reaction == 'laugh'" src="https://twemoji.maxcdn.com/2/svg/1f606.svg" :alt="$t('@.reactions.laugh')">
 | 
			
		||||
	<img v-if="reaction == 'hmm'" src="https://twemoji.maxcdn.com/2/svg/1f914.svg" :alt="$t('@.reactions.hmm')">
 | 
			
		||||
	<img v-if="reaction == 'surprise'" src="https://twemoji.maxcdn.com/2/svg/1f62e.svg" :alt="$t('@.reactions.surprise')">
 | 
			
		||||
	<img v-if="reaction == 'congrats'" src="https://twemoji.maxcdn.com/2/svg/1f389.svg" :alt="$t('@.reactions.congrats')">
 | 
			
		||||
	<img v-if="reaction == 'angry'" src="https://twemoji.maxcdn.com/2/svg/1f4a2.svg" :alt="$t('@.reactions.angry')">
 | 
			
		||||
	<img v-if="reaction == 'confused'" src="https://twemoji.maxcdn.com/2/svg/1f625.svg" :alt="$t('@.reactions.confused')">
 | 
			
		||||
	<img v-if="reaction == 'rip'" src="https://twemoji.maxcdn.com/2/svg/1f607.svg" :alt="$t('@.reactions.rip')">
 | 
			
		||||
	<template v-if="reaction == 'pudding'">
 | 
			
		||||
		<img v-if="$store.getters.isSignedIn && $store.state.settings.iLikeSushi" src="https://twemoji.maxcdn.com/2/svg/1f363.svg" :alt="$t('@.reactions.pudding')">
 | 
			
		||||
		<img v-else src="https://twemoji.maxcdn.com/2/svg/1f36e.svg" :alt="$t('@.reactions.pudding')">
 | 
			
		||||
	</template>
 | 
			
		||||
</span>
 | 
			
		||||
<mk-emoji :emoji="str.startsWith(':') ? null : str" :name="str.startsWith(':') ? str.substr(1, str.length - 2) : null" :is-reaction="true" :custom-emojis="customEmojis" :normal="true"/>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
@@ -21,7 +7,35 @@ import Vue from 'vue';
 | 
			
		||||
import i18n from '../../../i18n';
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	i18n: i18n(),
 | 
			
		||||
	props: ['reaction']
 | 
			
		||||
	props: {
 | 
			
		||||
		reaction: {
 | 
			
		||||
			type: String,
 | 
			
		||||
			required: true
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			customEmojis: (this.$root.getMetaSync() || { emojis: [] }).emojis || []
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		str(): any {
 | 
			
		||||
			switch (this.reaction) {
 | 
			
		||||
				case 'like': return '👍';
 | 
			
		||||
				case 'love': return '❤';
 | 
			
		||||
				case 'laugh': return '😆';
 | 
			
		||||
				case 'hmm': return '🤔';
 | 
			
		||||
				case 'surprise': return '😮';
 | 
			
		||||
				case 'congrats': return '🎉';
 | 
			
		||||
				case 'angry': return '💢';
 | 
			
		||||
				case 'confused': return '😥';
 | 
			
		||||
				case 'rip': return '😇';
 | 
			
		||||
				case 'pudding': return (this.$store.getters.isSignedIn && this.$store.state.settings.iLikeSushi) ? '🍣' : '🍮';
 | 
			
		||||
				case 'star': return '⭐';
 | 
			
		||||
				default: return this.reaction;
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
	<div class="backdrop" ref="backdrop" @click="close"></div>
 | 
			
		||||
	<div class="popover" :class="{ isMobile: $root.isMobile }" ref="popover">
 | 
			
		||||
		<p v-if="!$root.isMobile">{{ title }}</p>
 | 
			
		||||
		<div ref="buttons" :class="{ showFocus }">
 | 
			
		||||
		<div class="buttons" ref="buttons" :class="{ showFocus }">
 | 
			
		||||
			<button @click="react('like')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="1" :title="$t('@.reactions.like')" v-particle><mk-reaction-icon reaction="like"/></button>
 | 
			
		||||
			<button @click="react('love')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="2" :title="$t('@.reactions.love')" v-particle><mk-reaction-icon reaction="love"/></button>
 | 
			
		||||
			<button @click="react('laugh')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="3" :title="$t('@.reactions.laugh')" v-particle><mk-reaction-icon reaction="laugh"/></button>
 | 
			
		||||
@@ -15,6 +15,9 @@
 | 
			
		||||
			<button @click="react('rip')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="9" :title="$t('@.reactions.rip')" v-particle><mk-reaction-icon reaction="rip"/></button>
 | 
			
		||||
			<button @click="react('pudding')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="10" :title="$t('@.reactions.pudding')" v-particle><mk-reaction-icon reaction="pudding"/></button>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div v-if="enableEmojiReaction" class="text">
 | 
			
		||||
			<input v-model="text" placeholder="または絵文字を入力" @keyup.enter="reactText" @input="tryReactText" v-autocomplete="{ model: 'text' }">
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
@@ -23,6 +26,7 @@
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import i18n from '../../../i18n';
 | 
			
		||||
import anime from 'animejs';
 | 
			
		||||
import { emojiRegex } from '../../../../../misc/emoji-regex';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	i18n: i18n('common/views/components/reaction-picker.vue'),
 | 
			
		||||
@@ -56,6 +60,8 @@ export default Vue.extend({
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			title: this.$t('choose-reaction'),
 | 
			
		||||
			text: null,
 | 
			
		||||
			enableEmojiReaction: false,
 | 
			
		||||
			focus: null
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
@@ -94,6 +100,10 @@ export default Vue.extend({
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.$root.getMeta().then(meta => {
 | 
			
		||||
			this.enableEmojiReaction = meta.enableEmojiReaction;
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		this.$nextTick(() => {
 | 
			
		||||
			this.focus = 0;
 | 
			
		||||
 | 
			
		||||
@@ -143,6 +153,17 @@ export default Vue.extend({
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		reactText() {
 | 
			
		||||
			if (!this.text) return;
 | 
			
		||||
			this.react(this.text);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		tryReactText() {
 | 
			
		||||
			if (!this.text) return;
 | 
			
		||||
			if (!this.text.match(emojiRegex)) return;
 | 
			
		||||
			this.reactText();
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		onMouseover(e) {
 | 
			
		||||
			this.title = e.target.title;
 | 
			
		||||
		},
 | 
			
		||||
@@ -256,9 +277,9 @@ export default Vue.extend({
 | 
			
		||||
			color var(--popupFg)
 | 
			
		||||
			border-bottom solid var(--lineWidth) var(--faceDivider)
 | 
			
		||||
 | 
			
		||||
		> div
 | 
			
		||||
			padding 4px
 | 
			
		||||
			width 240px
 | 
			
		||||
		> .buttons
 | 
			
		||||
			padding 4px 4px 8px 4px
 | 
			
		||||
			width 216px
 | 
			
		||||
			text-align center
 | 
			
		||||
 | 
			
		||||
			&.showFocus
 | 
			
		||||
@@ -283,6 +304,9 @@ export default Vue.extend({
 | 
			
		||||
				font-size 24px
 | 
			
		||||
				border-radius 2px
 | 
			
		||||
 | 
			
		||||
				> *
 | 
			
		||||
					height 1em
 | 
			
		||||
 | 
			
		||||
				&:hover
 | 
			
		||||
					background var(--reactionPickerButtonHoverBg)
 | 
			
		||||
 | 
			
		||||
@@ -290,4 +314,29 @@ export default Vue.extend({
 | 
			
		||||
					background var(--primary)
 | 
			
		||||
					box-shadow inset 0 0.15em 0.3em rgba(27, 31, 35, 0.15)
 | 
			
		||||
 | 
			
		||||
		> .text
 | 
			
		||||
			width 216px
 | 
			
		||||
			padding 0 8px 8px 8px
 | 
			
		||||
 | 
			
		||||
			> input
 | 
			
		||||
				width 100%
 | 
			
		||||
				padding 10px
 | 
			
		||||
				margin 0
 | 
			
		||||
				text-align center
 | 
			
		||||
				font-size 16px
 | 
			
		||||
				color var(--desktopPostFormTextareaFg)
 | 
			
		||||
				background var(--desktopPostFormTextareaBg)
 | 
			
		||||
				outline none
 | 
			
		||||
				border solid 1px var(--primaryAlpha01)
 | 
			
		||||
				border-radius 4px
 | 
			
		||||
				transition border-color .2s ease
 | 
			
		||||
 | 
			
		||||
				&:hover
 | 
			
		||||
					border-color var(--primaryAlpha02)
 | 
			
		||||
					transition border-color .1s ease
 | 
			
		||||
 | 
			
		||||
				&:focus
 | 
			
		||||
					border-color var(--primaryAlpha05)
 | 
			
		||||
					transition border-color 0s ease
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -136,12 +136,8 @@ export default Vue.extend({
 | 
			
		||||
		&:hover
 | 
			
		||||
			background var(--reactionViewerButtonHoverBg)
 | 
			
		||||
 | 
			
		||||
	> .mk-reaction-icon
 | 
			
		||||
		font-size 1.4em
 | 
			
		||||
 | 
			
		||||
	> span
 | 
			
		||||
		font-size 1.1em
 | 
			
		||||
		line-height 32px
 | 
			
		||||
		vertical-align middle
 | 
			
		||||
		color var(--text)
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
	</template>
 | 
			
		||||
	<div v-if="data && !$store.state.i.twoFactorEnabled">
 | 
			
		||||
		<ol>
 | 
			
		||||
			<li>{{ $t('authenticator') }}<a href="https://support.google.com/accounts/answer/1066447" target="_blank">{{ $t('howtoinstall') }}</a></li>
 | 
			
		||||
			<li>{{ $t('authenticator') }}<a href="https://support.google.com/accounts/answer/1066447" rel="noopener" target="_blank">{{ $t('howtoinstall') }}</a></li>
 | 
			
		||||
			<li>{{ $t('scan') }}<br><img :src="data.qr"></li>
 | 
			
		||||
			<li>{{ $t('done') }}<br>
 | 
			
		||||
				<ui-input v-model="token">{{ $t('token') }}</ui-input>
 | 
			
		||||
 
 | 
			
		||||
@@ -93,12 +93,17 @@ export default Vue.extend({
 | 
			
		||||
					},
 | 
			
		||||
					plotOptions: {
 | 
			
		||||
						bar: {
 | 
			
		||||
							columnWidth: '90%'
 | 
			
		||||
							columnWidth: '80%'
 | 
			
		||||
						}
 | 
			
		||||
					},
 | 
			
		||||
					grid: {
 | 
			
		||||
						clipMarkers: false,
 | 
			
		||||
						borderColor: 'rgba(0, 0, 0, 0.1)'
 | 
			
		||||
						borderColor: 'rgba(0, 0, 0, 0.1)',
 | 
			
		||||
						xaxis: {
 | 
			
		||||
							lines: {
 | 
			
		||||
								show: true,
 | 
			
		||||
							}
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
					tooltip: {
 | 
			
		||||
						shared: true,
 | 
			
		||||
 
 | 
			
		||||
@@ -4,21 +4,21 @@
 | 
			
		||||
 | 
			
		||||
	<section v-if="enableTwitterIntegration">
 | 
			
		||||
		<header><fa :icon="['fab', 'twitter']"/> Twitter</header>
 | 
			
		||||
		<p v-if="$store.state.i.twitter">{{ $t('connected-to') }}: <a :href="`https://twitter.com/${$store.state.i.twitter.screenName}`" target="_blank">@{{ $store.state.i.twitter.screenName }}</a></p>
 | 
			
		||||
		<p v-if="$store.state.i.twitter">{{ $t('connected-to') }}: <a :href="`https://twitter.com/${$store.state.i.twitter.screenName}`" rel="nofollow noopener" target="_blank">@{{ $store.state.i.twitter.screenName }}</a></p>
 | 
			
		||||
		<ui-button v-if="$store.state.i.twitter" @click="disconnectTwitter">{{ $t('disconnect') }}</ui-button>
 | 
			
		||||
		<ui-button v-else @click="connectTwitter">{{ $t('connect') }}</ui-button>
 | 
			
		||||
	</section>
 | 
			
		||||
 | 
			
		||||
	<section v-if="enableDiscordIntegration">
 | 
			
		||||
		<header><fa :icon="['fab', 'discord']"/> Discord</header>
 | 
			
		||||
		<p v-if="$store.state.i.discord">{{ $t('connected-to') }}: <a :href="`https://discordapp.com/users/${$store.state.i.discord.id}`" target="_blank">@{{ $store.state.i.discord.username }}#{{ $store.state.i.discord.discriminator }}</a></p>
 | 
			
		||||
		<p v-if="$store.state.i.discord">{{ $t('connected-to') }}: <a :href="`https://discordapp.com/users/${$store.state.i.discord.id}`" rel="nofollow noopener" target="_blank">@{{ $store.state.i.discord.username }}#{{ $store.state.i.discord.discriminator }}</a></p>
 | 
			
		||||
		<ui-button v-if="$store.state.i.discord" @click="disconnectDiscord">{{ $t('disconnect') }}</ui-button>
 | 
			
		||||
		<ui-button v-else @click="connectDiscord">{{ $t('connect') }}</ui-button>
 | 
			
		||||
	</section>
 | 
			
		||||
 | 
			
		||||
	<section v-if="enableGithubIntegration">
 | 
			
		||||
		<header><fa :icon="['fab', 'github']"/> GitHub</header>
 | 
			
		||||
		<p v-if="$store.state.i.github">{{ $t('connected-to') }}: <a :href="`https://github.com/${$store.state.i.github.login}`" target="_blank">@{{ $store.state.i.github.login }}</a></p>
 | 
			
		||||
		<p v-if="$store.state.i.github">{{ $t('connected-to') }}: <a :href="`https://github.com/${$store.state.i.github.login}`" rel="nofollow noopener" target="_blank">@{{ $store.state.i.github.login }}</a></p>
 | 
			
		||||
		<ui-button v-if="$store.state.i.github" @click="disconnectGithub">{{ $t('disconnect') }}</ui-button>
 | 
			
		||||
		<ui-button v-else @click="connectGithub">{{ $t('connect') }}</ui-button>
 | 
			
		||||
	</section>
 | 
			
		||||
 
 | 
			
		||||
@@ -51,12 +51,12 @@
 | 
			
		||||
				<template #desc v-if="bannerUploading">{{ $t('uploading') }}<mk-ellipsis/></template>
 | 
			
		||||
			</ui-input>
 | 
			
		||||
 | 
			
		||||
			<ui-button @click="save(true)">{{ $t('save') }}</ui-button>
 | 
			
		||||
			<ui-button @click="save(true)"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
 | 
			
		||||
		</ui-form>
 | 
			
		||||
	</section>
 | 
			
		||||
 | 
			
		||||
	<section>
 | 
			
		||||
		<header>{{ $t('advanced') }}</header>
 | 
			
		||||
		<header><fa :icon="faCogs"/> {{ $t('advanced') }}</header>
 | 
			
		||||
 | 
			
		||||
		<div>
 | 
			
		||||
			<ui-switch v-model="isCat" @change="save(false)">{{ $t('is-cat') }}</ui-switch>
 | 
			
		||||
@@ -66,7 +66,7 @@
 | 
			
		||||
	</section>
 | 
			
		||||
 | 
			
		||||
	<section>
 | 
			
		||||
		<header>{{ $t('privacy') }}</header>
 | 
			
		||||
		<header><fa :icon="faUnlockAlt"/> {{ $t('privacy') }}</header>
 | 
			
		||||
 | 
			
		||||
		<div>
 | 
			
		||||
			<ui-switch v-model="isLocked" @change="save(false)">{{ $t('is-locked') }}</ui-switch>
 | 
			
		||||
@@ -76,7 +76,7 @@
 | 
			
		||||
	</section>
 | 
			
		||||
 | 
			
		||||
	<section v-if="enableEmail">
 | 
			
		||||
		<header>{{ $t('email') }}</header>
 | 
			
		||||
		<header><fa :icon="faEnvelope"/> {{ $t('email') }}</header>
 | 
			
		||||
 | 
			
		||||
		<div>
 | 
			
		||||
			<template v-if="$store.state.i.email != null">
 | 
			
		||||
@@ -84,12 +84,12 @@
 | 
			
		||||
				<ui-info v-else warn>{{ $t('email-not-verified') }}</ui-info>
 | 
			
		||||
			</template>
 | 
			
		||||
			<ui-input v-model="email" type="email"><span>{{ $t('email-address') }}</span></ui-input>
 | 
			
		||||
			<ui-button @click="updateEmail()">{{ $t('save') }}</ui-button>
 | 
			
		||||
			<ui-button @click="updateEmail()"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
 | 
			
		||||
		</div>
 | 
			
		||||
	</section>
 | 
			
		||||
 | 
			
		||||
	<section>
 | 
			
		||||
		<header>{{ $t('export') }}</header>
 | 
			
		||||
		<header><fa :icon="faBoxes"/> {{ $t('export-and-import') }}</header>
 | 
			
		||||
 | 
			
		||||
		<div>
 | 
			
		||||
			<ui-select v-model="exportTarget">
 | 
			
		||||
@@ -97,8 +97,12 @@
 | 
			
		||||
				<option value="following">{{ $t('export-targets.following-list') }}</option>
 | 
			
		||||
				<option value="mute">{{ $t('export-targets.mute-list') }}</option>
 | 
			
		||||
				<option value="blocking">{{ $t('export-targets.blocking-list') }}</option>
 | 
			
		||||
				<option value="user-lists">{{ $t('export-targets.user-lists') }}</option>
 | 
			
		||||
			</ui-select>
 | 
			
		||||
			<ui-button @click="doExport()"><fa :icon="faDownload"/> {{ $t('export') }}</ui-button>
 | 
			
		||||
			<ui-horizon-group class="fit-bottom">
 | 
			
		||||
				<ui-button @click="doExport()"><fa :icon="faDownload"/> {{ $t('export') }}</ui-button>
 | 
			
		||||
				<ui-button @click="doImport()" :disabled="!['following', 'user-lists'].includes(exportTarget)"><fa :icon="faUpload"/> {{ $t('import') }}</ui-button>
 | 
			
		||||
			</ui-horizon-group>
 | 
			
		||||
		</div>
 | 
			
		||||
	</section>
 | 
			
		||||
 | 
			
		||||
@@ -118,7 +122,8 @@ import { apiUrl, host } from '../../../../config';
 | 
			
		||||
import { toUnicode } from 'punycode';
 | 
			
		||||
import langmap from 'langmap';
 | 
			
		||||
import { unique } from '../../../../../../prelude/array';
 | 
			
		||||
import { faDownload } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import { faDownload, faUpload, faUnlockAlt, faBoxes, faCogs } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import { faSave, faEnvelope } from '@fortawesome/free-regular-svg-icons';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	i18n: i18n('common/views/components/profile-editor.vue'),
 | 
			
		||||
@@ -147,7 +152,7 @@ export default Vue.extend({
 | 
			
		||||
			avatarUploading: false,
 | 
			
		||||
			bannerUploading: false,
 | 
			
		||||
			exportTarget: 'notes',
 | 
			
		||||
			faDownload
 | 
			
		||||
			faDownload, faUpload, faSave, faEnvelope, faUnlockAlt, faBoxes, faCogs
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
@@ -284,11 +289,38 @@ export default Vue.extend({
 | 
			
		||||
				this.exportTarget == 'following' ? 'i/export-following' :
 | 
			
		||||
				this.exportTarget == 'mute' ? 'i/export-mute' :
 | 
			
		||||
				this.exportTarget == 'blocking' ? 'i/export-blocking' :
 | 
			
		||||
				null, {});
 | 
			
		||||
				this.exportTarget == 'user-lists' ? 'i/export-user-lists' :
 | 
			
		||||
				null, {}).then(() => {
 | 
			
		||||
					this.$root.dialog({
 | 
			
		||||
						type: 'info',
 | 
			
		||||
						text: this.$t('export-requested')
 | 
			
		||||
					});
 | 
			
		||||
				}).catch((e: any) => {
 | 
			
		||||
					this.$root.dialog({
 | 
			
		||||
						type: 'error',
 | 
			
		||||
						text: e.message
 | 
			
		||||
					});
 | 
			
		||||
				});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
			this.$root.dialog({
 | 
			
		||||
				type: 'info',
 | 
			
		||||
				text: this.$t('export-requested')
 | 
			
		||||
		doImport() {
 | 
			
		||||
			this.$chooseDriveFile().then(file => {
 | 
			
		||||
				this.$root.api(
 | 
			
		||||
					this.exportTarget == 'following' ? 'i/import-following' :
 | 
			
		||||
					this.exportTarget == 'user-lists' ? 'i/import-user-lists' :
 | 
			
		||||
					null, {
 | 
			
		||||
						fileId: file.id
 | 
			
		||||
				}).then(() => {
 | 
			
		||||
					this.$root.dialog({
 | 
			
		||||
						type: 'info',
 | 
			
		||||
						text: this.$t('import-requested')
 | 
			
		||||
					});
 | 
			
		||||
				}).catch((e: any) => {
 | 
			
		||||
					this.$root.dialog({
 | 
			
		||||
						type: 'error',
 | 
			
		||||
						text: e.message
 | 
			
		||||
					});
 | 
			
		||||
				});
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -159,7 +159,7 @@
 | 
			
		||||
	</template>
 | 
			
		||||
 | 
			
		||||
	<template v-if="page == null || page == 'notification'">
 | 
			
		||||
		<x-notification v-show="page == 'notification'"/>
 | 
			
		||||
		<x-notification/>
 | 
			
		||||
	</template>
 | 
			
		||||
 | 
			
		||||
	<template v-if="page == null || page == 'drive'">
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,7 @@
 | 
			
		||||
			</ui-select>
 | 
			
		||||
		</label>
 | 
			
		||||
 | 
			
		||||
		<a href="https://assets.msky.cafe/theme/list" target="_blank">{{ $t('find-more-theme') }}</a>
 | 
			
		||||
		<a href="https://assets.msky.cafe/theme/list" rel="noopener" target="_blank">{{ $t('find-more-theme') }}</a>
 | 
			
		||||
 | 
			
		||||
		<details class="creator">
 | 
			
		||||
			<summary><fa icon="palette"/> {{ $t('create-a-theme') }}</summary>
 | 
			
		||||
@@ -386,7 +386,7 @@ export default Vue.extend({
 | 
			
		||||
			height: 50px;
 | 
			
		||||
			background-color: #83D8FF;
 | 
			
		||||
			border-radius: 90px - 6;
 | 
			
		||||
			transition: background-color 200ms cubic-bezier(0.445, 0.05, 0.55, 0.95);
 | 
			
		||||
			transition: background-color 200ms cubic-bezier(0.445, 0.05, 0.55, 0.95) !important;
 | 
			
		||||
 | 
			
		||||
			&:before {
 | 
			
		||||
				content: 'Light';
 | 
			
		||||
@@ -418,14 +418,14 @@ export default Vue.extend({
 | 
			
		||||
			background-color: #FFCF96;
 | 
			
		||||
			border-radius: 50px;
 | 
			
		||||
			box-shadow: 0 2px 6px rgba(0,0,0,.3);
 | 
			
		||||
			transition: all 400ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
 | 
			
		||||
			transition: all 400ms cubic-bezier(0.68, -0.55, 0.265, 1.55) !important;
 | 
			
		||||
			transform:  rotate(-45deg);
 | 
			
		||||
 | 
			
		||||
			.crater {
 | 
			
		||||
				position: absolute;
 | 
			
		||||
				background-color: #E8CDA5;
 | 
			
		||||
				opacity: 0;
 | 
			
		||||
				transition: opacity 200ms ease-in-out;
 | 
			
		||||
				transition: opacity 200ms ease-in-out !important;
 | 
			
		||||
				border-radius: 100%;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
@@ -454,7 +454,7 @@ export default Vue.extend({
 | 
			
		||||
		.star {
 | 
			
		||||
			position: absolute;
 | 
			
		||||
			background-color: #ffffff;
 | 
			
		||||
			transition: all 300ms cubic-bezier(0.445, 0.05, 0.55, 0.95);
 | 
			
		||||
			transition: all 300ms cubic-bezier(0.445, 0.05, 0.55, 0.95) !important;
 | 
			
		||||
			border-radius: 50%;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -486,7 +486,7 @@ export default Vue.extend({
 | 
			
		||||
		.star--5,
 | 
			
		||||
		.star--6 {
 | 
			
		||||
			opacity: 0;
 | 
			
		||||
			transition: all 300ms 0 cubic-bezier(0.445, 0.05, 0.55, 0.95);
 | 
			
		||||
			transition: all 300ms 0 cubic-bezier(0.445, 0.05, 0.55, 0.95) !important;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		.star--4 {
 | 
			
		||||
@@ -559,13 +559,13 @@ export default Vue.extend({
 | 
			
		||||
					transform: translate3d(0,0,0);
 | 
			
		||||
				}
 | 
			
		||||
				.star--4 {
 | 
			
		||||
					transition: all 300ms 200ms cubic-bezier(0.445, 0.05, 0.55, 0.95);
 | 
			
		||||
					transition: all 300ms 200ms cubic-bezier(0.445, 0.05, 0.55, 0.95) !important;
 | 
			
		||||
				}
 | 
			
		||||
				.star--5 {
 | 
			
		||||
					transition: all 300ms 300ms cubic-bezier(0.445, 0.05, 0.55, 0.95);
 | 
			
		||||
					transition: all 300ms 300ms cubic-bezier(0.445, 0.05, 0.55, 0.95) !important;
 | 
			
		||||
				}
 | 
			
		||||
				.star--6 {
 | 
			
		||||
					transition: all 300ms 400ms cubic-bezier(0.445, 0.05, 0.55, 0.95);
 | 
			
		||||
					transition: all 300ms 400ms cubic-bezier(0.445, 0.05, 0.55, 0.95) !important;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,12 +3,14 @@
 | 
			
		||||
	<ol v-if="uploads.length > 0">
 | 
			
		||||
		<li v-for="ctx in uploads" :key="ctx.id">
 | 
			
		||||
			<div class="img" :style="{ backgroundImage: `url(${ ctx.img })` }"></div>
 | 
			
		||||
			<p class="name"><fa icon="spinner" pulse/>{{ ctx.name }}</p>
 | 
			
		||||
			<p class="status">
 | 
			
		||||
				<span class="initing" v-if="ctx.progress == undefined">{{ $t('waiting') }}<mk-ellipsis/></span>
 | 
			
		||||
				<span class="kb" v-if="ctx.progress != undefined">{{ String(Math.floor(ctx.progress.value / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }}<i>KB</i> / {{ String(Math.floor(ctx.progress.max / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }}<i>KB</i></span>
 | 
			
		||||
				<span class="percentage" v-if="ctx.progress != undefined">{{ Math.floor((ctx.progress.value / ctx.progress.max) * 100) }}</span>
 | 
			
		||||
			</p>
 | 
			
		||||
			<div class="top">
 | 
			
		||||
				<p class="name"><fa icon="spinner" pulse/>{{ ctx.name }}</p>
 | 
			
		||||
				<p class="status">
 | 
			
		||||
					<span class="initing" v-if="ctx.progress == undefined">{{ $t('waiting') }}<mk-ellipsis/></span>
 | 
			
		||||
					<span class="kb" v-if="ctx.progress != undefined">{{ String(Math.floor(ctx.progress.value / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }}<i>KB</i> / {{ String(Math.floor(ctx.progress.max / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }}<i>KB</i></span>
 | 
			
		||||
					<span class="percentage" v-if="ctx.progress != undefined">{{ Math.floor((ctx.progress.value / ctx.progress.max) * 100) }}</span>
 | 
			
		||||
				</p>
 | 
			
		||||
			</div>
 | 
			
		||||
			<progress v-if="ctx.progress != undefined && ctx.progress.value != ctx.progress.max" :value="ctx.progress.value" :max="ctx.progress.max"></progress>
 | 
			
		||||
			<div class="progress initing" v-if="ctx.progress == undefined"></div>
 | 
			
		||||
			<div class="progress waiting" v-if="ctx.progress != undefined && ctx.progress.value == ctx.progress.max"></div>
 | 
			
		||||
@@ -116,12 +118,17 @@ export default Vue.extend({
 | 
			
		||||
		list-style none
 | 
			
		||||
 | 
			
		||||
		> li
 | 
			
		||||
			display block
 | 
			
		||||
			display grid
 | 
			
		||||
			margin 8px 0 0 0
 | 
			
		||||
			padding 0
 | 
			
		||||
			height 36px
 | 
			
		||||
			width: 100%
 | 
			
		||||
			box-shadow 0 -1px 0 var(--primaryAlpha01)
 | 
			
		||||
			border-top solid 8px transparent
 | 
			
		||||
			grid-template-columns 36px calc(100% - 44px)
 | 
			
		||||
			grid-template-rows 1fr 8px
 | 
			
		||||
			column-gap 8px
 | 
			
		||||
			box-sizing content-box
 | 
			
		||||
 | 
			
		||||
			&:first-child
 | 
			
		||||
				margin 0
 | 
			
		||||
@@ -130,68 +137,62 @@ export default Vue.extend({
 | 
			
		||||
 | 
			
		||||
			> .img
 | 
			
		||||
				display block
 | 
			
		||||
				position absolute
 | 
			
		||||
				top 0
 | 
			
		||||
				left 0
 | 
			
		||||
				width 36px
 | 
			
		||||
				height 36px
 | 
			
		||||
				background-size cover
 | 
			
		||||
				background-position center center
 | 
			
		||||
				grid-column 1 / 2
 | 
			
		||||
				grid-row 1 / 3
 | 
			
		||||
 | 
			
		||||
			> .name
 | 
			
		||||
				display block
 | 
			
		||||
				position absolute
 | 
			
		||||
				top 0
 | 
			
		||||
				left 44px
 | 
			
		||||
				margin 0
 | 
			
		||||
				padding 0
 | 
			
		||||
				max-width 256px
 | 
			
		||||
				font-size 0.8em
 | 
			
		||||
				color var(--primaryAlpha07)
 | 
			
		||||
				white-space nowrap
 | 
			
		||||
				text-overflow ellipsis
 | 
			
		||||
				overflow hidden
 | 
			
		||||
 | 
			
		||||
				> [data-icon]
 | 
			
		||||
					margin-right 4px
 | 
			
		||||
 | 
			
		||||
			> .status
 | 
			
		||||
				display block
 | 
			
		||||
				position absolute
 | 
			
		||||
				top 0
 | 
			
		||||
				right 0
 | 
			
		||||
				margin 0
 | 
			
		||||
				padding 0
 | 
			
		||||
				font-size 0.8em
 | 
			
		||||
 | 
			
		||||
				> .initing
 | 
			
		||||
					color var(--primaryAlpha05)
 | 
			
		||||
 | 
			
		||||
				> .kb
 | 
			
		||||
					color var(--primaryAlpha05)
 | 
			
		||||
 | 
			
		||||
				> .percentage
 | 
			
		||||
					display inline-block
 | 
			
		||||
					width 48px
 | 
			
		||||
					text-align right
 | 
			
		||||
			> .top
 | 
			
		||||
				display flex
 | 
			
		||||
				grid-column 2 / 3
 | 
			
		||||
				grid-row 1 / 2
 | 
			
		||||
 | 
			
		||||
				> .name
 | 
			
		||||
					display block
 | 
			
		||||
					padding 0 8px 0 0
 | 
			
		||||
					margin 0
 | 
			
		||||
					font-size 0.8em
 | 
			
		||||
					color var(--primaryAlpha07)
 | 
			
		||||
					white-space nowrap
 | 
			
		||||
					text-overflow ellipsis
 | 
			
		||||
					overflow hidden
 | 
			
		||||
					flex-shrink 1
 | 
			
		||||
 | 
			
		||||
					&:after
 | 
			
		||||
						content '%'
 | 
			
		||||
					> [data-icon]
 | 
			
		||||
						margin-right 4px
 | 
			
		||||
 | 
			
		||||
				> .status
 | 
			
		||||
					display block
 | 
			
		||||
					margin 0 0 0 auto
 | 
			
		||||
					padding 0
 | 
			
		||||
					font-size 0.8em
 | 
			
		||||
					flex-shrink 0
 | 
			
		||||
 | 
			
		||||
					> .initing
 | 
			
		||||
						color var(--primaryAlpha05)
 | 
			
		||||
 | 
			
		||||
					> .kb
 | 
			
		||||
						color var(--primaryAlpha05)
 | 
			
		||||
 | 
			
		||||
					> .percentage
 | 
			
		||||
						display inline-block
 | 
			
		||||
						width 48px
 | 
			
		||||
						text-align right
 | 
			
		||||
 | 
			
		||||
						color var(--primaryAlpha07)
 | 
			
		||||
 | 
			
		||||
						&:after
 | 
			
		||||
							content '%'
 | 
			
		||||
 | 
			
		||||
			> progress
 | 
			
		||||
				display block
 | 
			
		||||
				position absolute
 | 
			
		||||
				bottom 0
 | 
			
		||||
				right 0
 | 
			
		||||
				margin 0
 | 
			
		||||
				width calc(100% - 44px)
 | 
			
		||||
				height 8px
 | 
			
		||||
				background transparent
 | 
			
		||||
				border none
 | 
			
		||||
				border-radius 4px
 | 
			
		||||
				overflow hidden
 | 
			
		||||
				grid-column 2 / 3
 | 
			
		||||
				grid-row 2 / 3
 | 
			
		||||
				z-index 2
 | 
			
		||||
 | 
			
		||||
				&::-webkit-progress-value
 | 
			
		||||
					background var(--primary)
 | 
			
		||||
@@ -201,12 +202,6 @@ export default Vue.extend({
 | 
			
		||||
 | 
			
		||||
			> .progress
 | 
			
		||||
				display block
 | 
			
		||||
				position absolute
 | 
			
		||||
				bottom 0
 | 
			
		||||
				right 0
 | 
			
		||||
				margin 0
 | 
			
		||||
				width calc(100% - 44px)
 | 
			
		||||
				height 8px
 | 
			
		||||
				border none
 | 
			
		||||
				border-radius 4px
 | 
			
		||||
				background linear-gradient(
 | 
			
		||||
@@ -221,6 +216,9 @@ export default Vue.extend({
 | 
			
		||||
				)
 | 
			
		||||
				background-size 32px 32px
 | 
			
		||||
				animation bg 1.5s linear infinite
 | 
			
		||||
				grid-column 2 / 3
 | 
			
		||||
				grid-row 2 / 3
 | 
			
		||||
				z-index 1
 | 
			
		||||
 | 
			
		||||
				&.initing
 | 
			
		||||
					opacity 0.3
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div v-if="playerEnabled" class="player" :style="`padding: ${(player.height || 0) / (player.width || 1) * 100}% 0 0`">
 | 
			
		||||
	<button class="disablePlayer" @click="playerEnabled = false" :title="$t('disable-player')"><fa icon="times"/></button>
 | 
			
		||||
	<iframe :src="player.url + (player.url.match(/\?/) ? '&autoplay=1&auto_play=1' : '?autoplay=1&auto_play=1')" :width="player.width || '100%'" :heigth="player.height || 250" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen />
 | 
			
		||||
</div>
 | 
			
		||||
<div v-else-if="tweetUrl && detail" class="twitter">
 | 
			
		||||
@@ -8,7 +9,7 @@
 | 
			
		||||
	</blockquote>
 | 
			
		||||
</div>
 | 
			
		||||
<div v-else class="mk-url-preview">
 | 
			
		||||
	<a :class="{ mini: narrow, compact }" :href="url" target="_blank" :title="url" v-if="!fetching">
 | 
			
		||||
	<a :class="{ mini: narrow, compact }" :href="url" rel="nofollow noopener" target="_blank" :title="url" v-if="!fetching">
 | 
			
		||||
		<div class="thumbnail" v-if="thumbnail" :style="`background-image: url('${thumbnail}')`">
 | 
			
		||||
			<button v-if="!playerEnabled && player.url" @click.prevent="playerEnabled = true" :title="$t('enable-player')"><fa :icon="['far', 'play-circle']"/></button>
 | 
			
		||||
		</div>
 | 
			
		||||
@@ -126,6 +127,22 @@ export default Vue.extend({
 | 
			
		||||
	position relative
 | 
			
		||||
	width 100%
 | 
			
		||||
 | 
			
		||||
	> button
 | 
			
		||||
		position absolute
 | 
			
		||||
		top -1.5em
 | 
			
		||||
		right 0
 | 
			
		||||
		font-size 1em
 | 
			
		||||
		width 1.5em
 | 
			
		||||
		height 1.5em
 | 
			
		||||
		padding 0
 | 
			
		||||
		margin 0
 | 
			
		||||
		color var(--text)
 | 
			
		||||
		background rgba(128, 128, 128, 0.2)
 | 
			
		||||
		opacity 0.7
 | 
			
		||||
 | 
			
		||||
		&:hover
 | 
			
		||||
			opacity 0.9
 | 
			
		||||
 | 
			
		||||
	> iframe
 | 
			
		||||
		height 100%
 | 
			
		||||
		left 0
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
<a class="mk-url" :href="url" :target="target">
 | 
			
		||||
<a class="mk-url" :href="url" :rel="rel" :target="target">
 | 
			
		||||
	<span class="schema">{{ schema }}//</span>
 | 
			
		||||
	<span class="hostname">{{ hostname }}</span>
 | 
			
		||||
	<span class="port" v-if="port != ''">:{{ port }}</span>
 | 
			
		||||
@@ -15,7 +15,7 @@ import Vue from 'vue';
 | 
			
		||||
import { toUnicode as decodePunycode } from 'punycode';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	props: ['url', 'target'],
 | 
			
		||||
	props: ['url', 'rel', 'target'],
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			schema: null,
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@
 | 
			
		||||
		<div class="no-users" v-if="inited && us.length == 0">
 | 
			
		||||
			<p>{{ $t('no-users') }}</p>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div class="user" v-for="user in us">
 | 
			
		||||
		<div class="user" v-for="user in us" :key="user.id">
 | 
			
		||||
			<mk-avatar class="avatar" :user="user"/>
 | 
			
		||||
			<div class="body" v-if="!iconOnly">
 | 
			
		||||
				<div class="name">
 | 
			
		||||
@@ -16,8 +16,9 @@
 | 
			
		||||
					<p class="username">@{{ user | acct }}</p>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="description" v-if="user.description" :title="user.description">
 | 
			
		||||
					<mfm :text="user.description" :is-note="false" :author="user" :i="$store.state.i" :custom-emojis="user.emojis" :should-break="false"/>
 | 
			
		||||
					<mfm :text="user.description" :is-note="false" :author="user" :i="$store.state.i" :custom-emojis="user.emojis" :should-break="false" :plain-text="true"/>
 | 
			
		||||
				</div>
 | 
			
		||||
				<mk-follow-button class="follow-button" v-if="$store.getters.isSignedIn && user.id != $store.state.i.id" :user="user" mini/>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
		<button class="more" :class="{ fetching: fetchingMoreUsers }" v-if="cursor != null" @click="fetchMoreUsers()" :disabled="fetchingMoreUsers">
 | 
			
		||||
@@ -160,6 +161,12 @@ export default Vue.extend({
 | 
			
		||||
				text-overflow ellipsis
 | 
			
		||||
				opacity 0.7
 | 
			
		||||
				font-size 14px
 | 
			
		||||
				padding-right 40px
 | 
			
		||||
 | 
			
		||||
			> .follow-button
 | 
			
		||||
				position absolute
 | 
			
		||||
				top 8px
 | 
			
		||||
				right 0px
 | 
			
		||||
 | 
			
		||||
	> .more
 | 
			
		||||
		display block
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import i18n from '../../../i18n';
 | 
			
		||||
import copyToClipboard from '../../../common/scripts/copy-to-clipboard';
 | 
			
		||||
import { faExclamationCircle, faMicrophoneSlash } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import { faSnowflake } from '@fortawesome/free-regular-svg-icons';
 | 
			
		||||
 | 
			
		||||
@@ -27,19 +26,23 @@ export default Vue.extend({
 | 
			
		||||
			icon: ['fas', 'list'],
 | 
			
		||||
			text: this.$t('push-to-list'),
 | 
			
		||||
			action: this.pushList
 | 
			
		||||
		}, null, {
 | 
			
		||||
			icon: this.user.isMuted ? ['fas', 'eye'] : ['far', 'eye-slash'],
 | 
			
		||||
			text: this.user.isMuted ? this.$t('unmute') : this.$t('mute'),
 | 
			
		||||
			action: this.toggleMute
 | 
			
		||||
		}, {
 | 
			
		||||
			icon: 'ban',
 | 
			
		||||
			text: this.user.isBlocking ? this.$t('unblock') : this.$t('block'),
 | 
			
		||||
			action: this.toggleBlock
 | 
			
		||||
		}, null, {
 | 
			
		||||
			icon: faExclamationCircle,
 | 
			
		||||
			text: this.$t('report-abuse'),
 | 
			
		||||
			action: this.reportAbuse
 | 
			
		||||
		}];
 | 
			
		||||
		}] as any;
 | 
			
		||||
		
 | 
			
		||||
		if (this.$store.getters.isSignedIn && this.$store.state.i.id != this.user.id) {
 | 
			
		||||
			menu = menu.concat([null, {
 | 
			
		||||
				icon: this.user.isMuted ? ['fas', 'eye'] : ['far', 'eye-slash'],
 | 
			
		||||
				text: this.user.isMuted ? this.$t('unmute') : this.$t('mute'),
 | 
			
		||||
				action: this.toggleMute
 | 
			
		||||
			}, {
 | 
			
		||||
				icon: 'ban',
 | 
			
		||||
				text: this.user.isBlocking ? this.$t('unblock') : this.$t('block'),
 | 
			
		||||
				action: this.toggleBlock
 | 
			
		||||
			}, null, {
 | 
			
		||||
				icon: faExclamationCircle,
 | 
			
		||||
				text: this.$t('report-abuse'),
 | 
			
		||||
				action: this.reportAbuse
 | 
			
		||||
			}]);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (this.$store.getters.isSignedIn && (this.$store.state.i.isAdmin || this.$store.state.i.isModerator)) {
 | 
			
		||||
			menu = menu.concat([null, {
 | 
			
		||||
@@ -89,8 +92,10 @@ export default Vue.extend({
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		toggleMute() {
 | 
			
		||||
		async toggleMute() {
 | 
			
		||||
			if (this.user.isMuted) {
 | 
			
		||||
				if (!await this.getConfirmed(this.$t('unmute-confirm'))) return;
 | 
			
		||||
 | 
			
		||||
				this.$root.api('mute/delete', {
 | 
			
		||||
					userId: this.user.id
 | 
			
		||||
				}).then(() => {
 | 
			
		||||
@@ -102,6 +107,8 @@ export default Vue.extend({
 | 
			
		||||
					});
 | 
			
		||||
				});
 | 
			
		||||
			} else {
 | 
			
		||||
				if (!await this.getConfirmed(this.$t('mute-confirm'))) return;
 | 
			
		||||
 | 
			
		||||
				this.$root.api('mute/create', {
 | 
			
		||||
					userId: this.user.id
 | 
			
		||||
				}).then(() => {
 | 
			
		||||
@@ -115,8 +122,10 @@ export default Vue.extend({
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		toggleBlock() {
 | 
			
		||||
		async toggleBlock() {
 | 
			
		||||
			if (this.user.isBlocking) {
 | 
			
		||||
				if (!await this.getConfirmed(this.$t('unblock-confirm'))) return;
 | 
			
		||||
 | 
			
		||||
				this.$root.api('blocking/delete', {
 | 
			
		||||
					userId: this.user.id
 | 
			
		||||
				}).then(() => {
 | 
			
		||||
@@ -128,6 +137,8 @@ export default Vue.extend({
 | 
			
		||||
					});
 | 
			
		||||
				});
 | 
			
		||||
			} else {
 | 
			
		||||
				if (!await this.getConfirmed(this.$t('block-confirm'))) return;
 | 
			
		||||
 | 
			
		||||
				this.$root.api('blocking/create', {
 | 
			
		||||
					userId: this.user.id
 | 
			
		||||
				}).then(() => {
 | 
			
		||||
@@ -164,7 +175,9 @@ export default Vue.extend({
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		toggleSilence() {
 | 
			
		||||
		async toggleSilence() {
 | 
			
		||||
			if (!await this.getConfirmed(this.$t(this.user.isSilenced ? 'unsilence-confirm' : 'silence-confirm'))) return;
 | 
			
		||||
 | 
			
		||||
			this.$root.api(this.user.isSilenced ? 'admin/unsilence-user' : 'admin/silence-user', {
 | 
			
		||||
				userId: this.user.id
 | 
			
		||||
			}).then(() => {
 | 
			
		||||
@@ -181,7 +194,9 @@ export default Vue.extend({
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		toggleSuspend() {
 | 
			
		||||
		async toggleSuspend() {
 | 
			
		||||
			if (!await this.getConfirmed(this.$t(this.user.isSuspended ? 'unsuspend-confirm' : 'suspend-confirm'))) return;
 | 
			
		||||
 | 
			
		||||
			this.$root.api(this.user.isSuspended ? 'admin/unsuspend-user' : 'admin/suspend-user', {
 | 
			
		||||
				userId: this.user.id
 | 
			
		||||
			}).then(() => {
 | 
			
		||||
@@ -196,7 +211,18 @@ export default Vue.extend({
 | 
			
		||||
					text: e
 | 
			
		||||
				});
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		async getConfirmed(text: string): Promise<Boolean> {
 | 
			
		||||
			const confirm = await this.$root.dialog({
 | 
			
		||||
				type: 'warning',
 | 
			
		||||
				showCancelButton: true,
 | 
			
		||||
				title: 'confirm',
 | 
			
		||||
				text,
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			return !confirm.canceled;
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@
 | 
			
		||||
 | 
			
		||||
	<div class="xroyrflcmhhtmlwmyiwpfqiirqokfueb">
 | 
			
		||||
		<div ref="chart" class="chart"></div>
 | 
			
		||||
		<x-hashtag-tl :tag-tl="tagTl" class="tl"/>
 | 
			
		||||
		<x-hashtag-tl :tag-tl="tagTl" class="tl" :key="JSON.stringify(tagTl)"/>
 | 
			
		||||
	</div>
 | 
			
		||||
</x-column>
 | 
			
		||||
</template>
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@
 | 
			
		||||
		<div class="is-remote" v-if="note.user.host != null">
 | 
			
		||||
			<details>
 | 
			
		||||
				<summary><fa icon="exclamation-triangle"/> {{ $t('@.is-remote-post') }}</summary>
 | 
			
		||||
				<a :href="note.url || note.uri" target="_blank">{{ $t('@.view-on-remote') }}</a>
 | 
			
		||||
				<a :href="note.url || note.uri" rel="nofollow noopener" target="_blank">{{ $t('@.view-on-remote') }}</a>
 | 
			
		||||
			</details>
 | 
			
		||||
		</div>
 | 
			
		||||
		<mk-note :note="note" :detail="true" :key="note.id"/>
 | 
			
		||||
 
 | 
			
		||||
@@ -157,6 +157,7 @@ export default Vue.extend({
 | 
			
		||||
				// オーバーフローしたら古い投稿は捨てる
 | 
			
		||||
				if (this.notes.length >= displayLimit) {
 | 
			
		||||
					this.notes = this.notes.slice(0, displayLimit);
 | 
			
		||||
					this.cursor = this.notes[this.notes.length - 1].id
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				this.queue.push(note);
 | 
			
		||||
@@ -165,6 +166,7 @@ export default Vue.extend({
 | 
			
		||||
 | 
			
		||||
		append(note) {
 | 
			
		||||
			this.notes.push(note);
 | 
			
		||||
			this.cursor = this.notes[this.notes.length - 1].id
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		releaseQueue() {
 | 
			
		||||
 
 | 
			
		||||
@@ -85,7 +85,7 @@ export default Vue.extend({
 | 
			
		||||
			this.makePromise = cursor => this.$root.api('users/notes', {
 | 
			
		||||
				userId: this.user.id,
 | 
			
		||||
				limit: fetchLimit + 1,
 | 
			
		||||
				untilId: cursor ? cursor : undefined,
 | 
			
		||||
				untilDate: cursor ? cursor : new Date().getTime() + 1000 * 86400 * 365,
 | 
			
		||||
				withFiles: this.withFiles,
 | 
			
		||||
				includeMyRenotes: this.$store.state.settings.showMyRenotes,
 | 
			
		||||
				includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes,
 | 
			
		||||
@@ -95,7 +95,7 @@ export default Vue.extend({
 | 
			
		||||
					notes.pop();
 | 
			
		||||
					return {
 | 
			
		||||
						notes: notes,
 | 
			
		||||
						cursor: notes[notes.length - 1].id
 | 
			
		||||
						cursor: new Date(notes[notes.length - 1].createdAt).getTime()
 | 
			
		||||
					};
 | 
			
		||||
				} else {
 | 
			
		||||
					return {
 | 
			
		||||
@@ -172,7 +172,7 @@ export default Vue.extend({
 | 
			
		||||
					},
 | 
			
		||||
					plotOptions: {
 | 
			
		||||
						bar: {
 | 
			
		||||
							columnWidth: '90%'
 | 
			
		||||
							columnWidth: '80%'
 | 
			
		||||
						}
 | 
			
		||||
					},
 | 
			
		||||
					grid: {
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@
 | 
			
		||||
		<div class="is-remote" v-if="user.host != null">
 | 
			
		||||
			<details>
 | 
			
		||||
				<summary><fa icon="exclamation-triangle"/> {{ $t('@.is-remote-user') }}</summary>
 | 
			
		||||
				<a :href="user.url || user.uri" target="_blank">{{ $t('@.view-on-remote') }}</a>
 | 
			
		||||
				<a :href="user.url || user.uri" rel="nofollow noopener" target="_blank">{{ $t('@.view-on-remote') }}</a>
 | 
			
		||||
			</details>
 | 
			
		||||
		</div>
 | 
			
		||||
		<header :style="bannerStyle">
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,7 @@
 | 
			
		||||
					<option value="hashtags">{{ $t('@.widgets.hashtags') }}</option>
 | 
			
		||||
					<option value="posts-monitor">{{ $t('@.widgets.posts-monitor') }}</option>
 | 
			
		||||
					<option value="server">{{ $t('@.widgets.server') }}</option>
 | 
			
		||||
					<option value="queue">{{ $t('@.widgets.queue') }}</option>
 | 
			
		||||
					<option value="nav">{{ $t('@.widgets.nav') }}</option>
 | 
			
		||||
					<option value="tips">{{ $t('@.widgets.tips') }}</option>
 | 
			
		||||
				</select>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
	<h1>{{ $t('share-with', { name }) }}</h1>
 | 
			
		||||
	<div>
 | 
			
		||||
		<mk-signin v-if="!$store.getters.isSignedIn"/>
 | 
			
		||||
		<mk-post-form v-else-if="!posted" :initial-text="text" :instant="true" @posted="posted = true"/>
 | 
			
		||||
		<mk-post-form v-else-if="!posted" :initial-text="template" :instant="true" @posted="posted = true"/>
 | 
			
		||||
		<p v-if="posted" class="posted"><fa icon="check"/></p>
 | 
			
		||||
	</div>
 | 
			
		||||
	<ui-button class="close" v-if="posted" @click="close">{{ $t('@.close') }}</ui-button>
 | 
			
		||||
@@ -20,9 +20,21 @@ export default Vue.extend({
 | 
			
		||||
		return {
 | 
			
		||||
			name: null,
 | 
			
		||||
			posted: false,
 | 
			
		||||
			text: new URLSearchParams(location.search).get('text')
 | 
			
		||||
			text: new URLSearchParams(location.search).get('text'),
 | 
			
		||||
			url: new URLSearchParams(location.search).get('url'),
 | 
			
		||||
			title: new URLSearchParams(location.search).get('title'),
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		template(): string {
 | 
			
		||||
			let t = '';
 | 
			
		||||
			if (this.title && this.url) t += `【[${this.title}](${this.url})】\n`;
 | 
			
		||||
			if (this.title && !this.url) t += `【${this.title}】\n`;
 | 
			
		||||
			if (this.text) t += `${this.text}\n`;
 | 
			
		||||
			if (!this.title && this.url) t += `${this.url}`;
 | 
			
		||||
			return t.trim();
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		close() {
 | 
			
		||||
			window.close();
 | 
			
		||||
@@ -31,3 +31,4 @@ Vue.component('mkw-version', wVersion);
 | 
			
		||||
Vue.component('mkw-hashtags', wHashtags);
 | 
			
		||||
Vue.component('mkw-instance', wInstance);
 | 
			
		||||
Vue.component('mkw-post-form', wPostForm);
 | 
			
		||||
Vue.component('mkw-queue', () => import('./queue.vue').then(m => m.default));
 | 
			
		||||
 
 | 
			
		||||
@@ -21,14 +21,7 @@
 | 
			
		||||
					<fa :icon="['far', 'laugh']"/>
 | 
			
		||||
				</button>
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="files" 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>
 | 
			
		||||
						<img class="remove" @click="detachMedia(file.id)" src="/assets/desktop/remove.png" :title="$t('attach-cancel')" alt=""/>
 | 
			
		||||
					</div>
 | 
			
		||||
				</x-draggable>
 | 
			
		||||
			</div>
 | 
			
		||||
			<x-post-form-attaches class="files" :files="files" :detachMediaFn="detachMedia"/>
 | 
			
		||||
			<input ref="file" type="file" multiple="multiple" tabindex="-1" @change="onChangeFile"/>
 | 
			
		||||
			<mk-uploader ref="uploader" @uploaded="attachMedia"/>
 | 
			
		||||
			<footer>
 | 
			
		||||
@@ -45,7 +38,7 @@
 | 
			
		||||
import define from '../../../common/define-widget';
 | 
			
		||||
import i18n from '../../../i18n';
 | 
			
		||||
import insertTextAtCursor from 'insert-text-at-cursor';
 | 
			
		||||
import * as XDraggable from 'vuedraggable';
 | 
			
		||||
import XPostFormAttaches from '../components/post-form-attaches.vue';
 | 
			
		||||
 | 
			
		||||
export default define({
 | 
			
		||||
	name: 'post-form',
 | 
			
		||||
@@ -56,7 +49,7 @@ export default define({
 | 
			
		||||
	i18n: i18n('desktop/views/widgets/post-form.vue'),
 | 
			
		||||
 | 
			
		||||
	components: {
 | 
			
		||||
		XDraggable
 | 
			
		||||
		XPostFormAttaches
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	data() {
 | 
			
		||||
@@ -176,10 +169,22 @@ export default define({
 | 
			
		||||
		post() {
 | 
			
		||||
			this.posting = true;
 | 
			
		||||
 | 
			
		||||
			let visibility = 'public';
 | 
			
		||||
			let localOnly = false;
 | 
			
		||||
 | 
			
		||||
			const m = this.$store.state.settings.defaultNoteVisibility.match(/^local-(.+)/);
 | 
			
		||||
			if (m) {
 | 
			
		||||
				visibility = m[1];
 | 
			
		||||
				localOnly = true;
 | 
			
		||||
			} else {
 | 
			
		||||
				visibility = this.$store.state.settings.defaultNoteVisibility;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			this.$root.api('notes/create', {
 | 
			
		||||
				text: this.text == '' ? undefined : this.text,
 | 
			
		||||
				fileIds: this.files.length > 0 ? this.files.map(f => f.id) : undefined,
 | 
			
		||||
				visibility: this.$store.state.settings.defaultNoteVisibility
 | 
			
		||||
				visibility,
 | 
			
		||||
				localOnly,
 | 
			
		||||
			}).then(data => {
 | 
			
		||||
				this.clear();
 | 
			
		||||
			}).catch(err => {
 | 
			
		||||
@@ -237,38 +242,6 @@ export default define({
 | 
			
		||||
				& + .emoji
 | 
			
		||||
					opacity 0.7
 | 
			
		||||
 | 
			
		||||
	> .files
 | 
			
		||||
		> div
 | 
			
		||||
			padding 4px
 | 
			
		||||
 | 
			
		||||
			&:after
 | 
			
		||||
				content ""
 | 
			
		||||
				display block
 | 
			
		||||
				clear both
 | 
			
		||||
 | 
			
		||||
			> div
 | 
			
		||||
				float left
 | 
			
		||||
				border solid 4px transparent
 | 
			
		||||
				cursor move
 | 
			
		||||
 | 
			
		||||
				&:hover > .remove
 | 
			
		||||
					display block
 | 
			
		||||
 | 
			
		||||
				> .img
 | 
			
		||||
					width 64px
 | 
			
		||||
					height 64px
 | 
			
		||||
					background-size cover
 | 
			
		||||
					background-position center center
 | 
			
		||||
 | 
			
		||||
				> .remove
 | 
			
		||||
					display none
 | 
			
		||||
					position absolute
 | 
			
		||||
					top -6px
 | 
			
		||||
					right -6px
 | 
			
		||||
					width 16px
 | 
			
		||||
					height 16px
 | 
			
		||||
					cursor pointer
 | 
			
		||||
 | 
			
		||||
	> input[type=file]
 | 
			
		||||
		display none
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										170
									
								
								src/client/app/common/views/widgets/queue.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								src/client/app/common/views/widgets/queue.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,170 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div>
 | 
			
		||||
	<ui-container :show-header="!props.compact">
 | 
			
		||||
		<template #header><fa :icon="faTasks"/>Queue</template>
 | 
			
		||||
 | 
			
		||||
		<div class="mntrproz">
 | 
			
		||||
			<div>
 | 
			
		||||
				<b>In</b>
 | 
			
		||||
				<span v-if="latestStats">{{ latestStats.inbox.activeSincePrevTick | number }} / {{ latestStats.inbox.delayed | number }}</span>
 | 
			
		||||
				<div ref="in"></div>
 | 
			
		||||
			</div>
 | 
			
		||||
			<div>
 | 
			
		||||
				<b>Out</b>
 | 
			
		||||
				<span v-if="latestStats">{{ latestStats.deliver.activeSincePrevTick | number }} / {{ latestStats.deliver.delayed | number }}</span>
 | 
			
		||||
				<div ref="out"></div>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
	</ui-container>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import define from '../../define-widget';
 | 
			
		||||
import { faTasks } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import ApexCharts from 'apexcharts';
 | 
			
		||||
 | 
			
		||||
export default define({
 | 
			
		||||
	name: 'queue',
 | 
			
		||||
	props: () => ({
 | 
			
		||||
		compact: false
 | 
			
		||||
	})
 | 
			
		||||
}).extend({
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			stats: [],
 | 
			
		||||
			inChart: null,
 | 
			
		||||
			outChart: null,
 | 
			
		||||
			faTasks
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	watch: {
 | 
			
		||||
		stats(stats) {
 | 
			
		||||
			this.inChart.updateSeries([{
 | 
			
		||||
				type: 'area',
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.inbox.activeSincePrevTick }))
 | 
			
		||||
			}, {
 | 
			
		||||
				type: 'area',
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.inbox.active }))
 | 
			
		||||
			}, {
 | 
			
		||||
				type: 'line',
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.inbox.waiting }))
 | 
			
		||||
			}, {
 | 
			
		||||
				type: 'line',
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.inbox.delayed }))
 | 
			
		||||
			}]);
 | 
			
		||||
			this.outChart.updateSeries([{
 | 
			
		||||
				type: 'area',
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.deliver.activeSincePrevTick }))
 | 
			
		||||
			}, {
 | 
			
		||||
				type: 'area',
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.deliver.active }))
 | 
			
		||||
			}, {
 | 
			
		||||
				type: 'line',
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.deliver.waiting }))
 | 
			
		||||
			}, {
 | 
			
		||||
				type: 'line',
 | 
			
		||||
				data: stats.map((x, i) => ({ x: i, y: x.deliver.delayed }))
 | 
			
		||||
			}]);
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	computed: {
 | 
			
		||||
		latestStats(): any {
 | 
			
		||||
			return this.stats[this.stats.length - 1];
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	mounted() {
 | 
			
		||||
		const chartOpts = {
 | 
			
		||||
			chart: {
 | 
			
		||||
				type: 'area',
 | 
			
		||||
				height: 70,
 | 
			
		||||
				animations: {
 | 
			
		||||
					dynamicAnimation: {
 | 
			
		||||
						enabled: false
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				sparkline: {
 | 
			
		||||
					enabled: true,
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			tooltip: {
 | 
			
		||||
				enabled: false
 | 
			
		||||
			},
 | 
			
		||||
			stroke: {
 | 
			
		||||
				curve: 'straight',
 | 
			
		||||
				width: 1
 | 
			
		||||
			},
 | 
			
		||||
			colors: ['#00E396', '#00BCD4', '#FFB300', '#e53935'],
 | 
			
		||||
			series: [{ data: [] }, { data: [] }, { data: [] }, { data: [] }] as any,
 | 
			
		||||
			yaxis: {
 | 
			
		||||
				min: 0,
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		this.inChart = new ApexCharts(this.$refs.in, chartOpts);
 | 
			
		||||
		this.outChart = new ApexCharts(this.$refs.out, chartOpts);
 | 
			
		||||
 | 
			
		||||
		this.inChart.render();
 | 
			
		||||
		this.outChart.render();
 | 
			
		||||
 | 
			
		||||
		const connection = this.$root.stream.useSharedConnection('queueStats');
 | 
			
		||||
		connection.on('stats', this.onStats);
 | 
			
		||||
		connection.on('statsLog', this.onStatsLog);
 | 
			
		||||
		connection.send('requestLog', {
 | 
			
		||||
			id: Math.random().toString().substr(2, 8),
 | 
			
		||||
			length: 50
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		this.$once('hook:beforeDestroy', () => {
 | 
			
		||||
			connection.dispose();
 | 
			
		||||
			this.inChart.destroy();
 | 
			
		||||
			this.outChart.destroy();
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	methods: {
 | 
			
		||||
		func() {
 | 
			
		||||
			this.props.compact = !this.props.compact;
 | 
			
		||||
			this.save();
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		onStats(stats) {
 | 
			
		||||
			this.stats.push(stats);
 | 
			
		||||
			if (this.stats.length > 50) this.stats.shift();
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		onStatsLog(statsLog) {
 | 
			
		||||
			for (const stats of statsLog.reverse()) {
 | 
			
		||||
				this.onStats(stats);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
.mntrproz
 | 
			
		||||
	display flex
 | 
			
		||||
	padding 4px
 | 
			
		||||
 | 
			
		||||
	> div
 | 
			
		||||
		width 50%
 | 
			
		||||
		padding 4px
 | 
			
		||||
 | 
			
		||||
		> b
 | 
			
		||||
			display block
 | 
			
		||||
			font-size 12px
 | 
			
		||||
			color var(--text)
 | 
			
		||||
 | 
			
		||||
		> span
 | 
			
		||||
			position absolute
 | 
			
		||||
			top 4px
 | 
			
		||||
			right 4px
 | 
			
		||||
			opacity 0.7
 | 
			
		||||
			font-size 12px
 | 
			
		||||
			color var(--text)
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
		<div class="mkw-rss--body" :data-mobile="platform == 'mobile'">
 | 
			
		||||
			<p class="fetching" v-if="fetching"><fa icon="spinner" pulse fixed-width/>{{ $t('@.loading') }}<mk-ellipsis/></p>
 | 
			
		||||
			<div class="feed" v-else>
 | 
			
		||||
				<a v-for="item in items" :href="item.link" target="_blank" :title="item.title">{{ item.title }}</a>
 | 
			
		||||
				<a v-for="item in items" :href="item.link" rel="nofollow noopener" target="_blank" :title="item.title">{{ item.title }}</a>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
	</ui-container>
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ import MkSelectDrive from './views/pages/selectdrive.vue';
 | 
			
		||||
import MkDrive from './views/pages/drive.vue';
 | 
			
		||||
import MkMessagingRoom from './views/pages/messaging-room.vue';
 | 
			
		||||
import MkReversi from './views/pages/games/reversi.vue';
 | 
			
		||||
import MkShare from './views/pages/share.vue';
 | 
			
		||||
import MkShare from '../common/views/pages/share.vue';
 | 
			
		||||
import MkFollow from '../common/views/pages/follow.vue';
 | 
			
		||||
import MkNotFound from '../common/views/pages/not-found.vue';
 | 
			
		||||
import MkSettings from './views/pages/settings.vue';
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user