Compare commits
	
		
			418 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | bb9ab31d5e | ||
|   | 9def80af8a | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | 9256bcdbe4 | ||
|   | 9b775022bc | ||
|   | 32371ed2bd | ||
|   | 8b98c08a81 | ||
|   | 7cf72f7447 | ||
|   | 913385b10d | ||
|   | 7306468d08 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | 11e5667778 | ||
|   | 38cc02e261 | ||
|   | d52cf46cc1 | ||
|   | c6110dd996 | ||
|   | 51d8de2c38 | ||
|   | 4455a1aa9d | ||
|   | 040d395ddb | ||
|   | 8296cac636 | ||
|   | 3eafe8b87d | ||
|   | c01512e261 | ||
|   | e5cf3aecd5 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | a8f90b41b7 | ||
|   | b79169b975 | ||
|   | 437d52e2ed | ||
|   | 1329721440 | ||
|   | 6affb4fe97 | ||
|   | 15395686aa | ||
|   | 047bcc78ad | ||
|   | 9df68618f2 | ||
|   | 732db087ab | ||
|   | 0e95b33b6a | ||
|   | 816ae7eb7e | ||
|   | 5a5ff194fa | ||
|   | a60edf9cff | ||
|   | 1c2dbb914e | ||
|   | 9c170c426b | ||
|   | c6239c8ad9 | ||
|   | 159b361bac | ||
|   | 160f64c18e | ||
|   | e5916b3789 | ||
|   | 70982b33c5 | ||
|   | b4d614ad45 | ||
|   | 6d2ef41b37 | ||
|   | e102237aab | ||
|   | 665af87031 | ||
|   | 6f4e439697 | ||
|   | 742dcf35c9 | ||
|   | 9cd70c568c | ||
|   | facabf274f | ||
|   | e3ab51022f | ||
|   | d278367cf9 | ||
|   | a70ced8e90 | ||
|   | 567cedc7cc | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | 9b3af6efcd | ||
|   | d9edc1eb1d | ||
|   | 65e46b5cec | ||
|   | e00b5f11cb | ||
|   | 6b53d5f269 | ||
|   | 59c80ab140 | ||
|   | da323aad36 | ||
|   | 7c1611c939 | ||
|   | ab861beabe | ||
|   | d260e93161 | ||
|   | 65a1855606 | ||
|   | c0e08e44a4 | ||
|   | 5c1cebcef4 | ||
|   | af25d3a85e | ||
|   | 8cb7183107 | ||
|   | 1bf228d73e | ||
|   | d952b996e6 | ||
|   | 1e407c4059 | ||
|   | b56d1fa60e | ||
|   | 6340f95bfc | ||
|   | 3c08dacf6c | ||
|   | 2908124ad8 | ||
|   | 3d62faaaf2 | ||
|   | b1efa9700d | ||
|   | 1d08af5747 | ||
|   | 2f82d0db87 | ||
|   | d88159907d | ||
|   | 9ed9fbef65 | ||
|   | 86c2e5bb91 | ||
|   | d9b548de1a | ||
|   | 2271c6cbd8 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | c4d4293c46 | ||
|   | 39bdfb6e0d | ||
|   | 1003fd393e | ||
|   | 2ede3c0864 | ||
|   | 674764a035 | ||
|   | a780e7b936 | ||
|   | 03d0ce1f89 | ||
|   | 4182a0cf4c | ||
|   | 305915611e | ||
|   | b0cd59bed9 | ||
|   | 599dcbaa48 | ||
|   | 2806dc98bd | ||
|   | bdc52dc114 | ||
|   | 3f6b9e554c | ||
|   | f47ad7bf31 | ||
|   | f992f72d31 | ||
|   | a26f1db2cb | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | 361ab00c61 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | f5cbcf3452 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | 599386190a | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | ec541d3cd0 | ||
|   | 3199819ded | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | ccf04d63ec | ||
|   | b9f5fca333 | ||
|   | b6a330928d | ||
|   | 1c65cb3e36 | ||
|   | dbb8c99efb | ||
|   | 0adcb646fe | ||
|   | a1ef70c0bf | ||
|   | 75cd580c3a | ||
|   | e05acb8d18 | ||
|   | 10af684804 | ||
|   | 3e897727ca | ||
|   | d0570d7fe3 | ||
|   | 5cf1956135 | ||
|   | 0b98a2364b | ||
|   | fff307d4bb | ||
|   | 2b7782ba03 | ||
|   | 96d961ee80 | ||
|   | 9f064d76d9 | ||
|   | 2e39106c4b | ||
|   | 1305006391 | ||
|   | 04650464f3 | ||
|   | 3bc7e1e35c | ||
|   | 7019ddbfc7 | ||
|   | 106d990bd2 | ||
|   | b29eb29556 | ||
|   | aeac1854ed | ||
|   | dbc57dd0d3 | ||
|   | 328a87609e | ||
|   | 5d848f3900 | ||
|   | cf4ed45fe4 | ||
|   | 07293094d5 | ||
|   | 0917696c86 | ||
|   | 030a027366 | ||
|   | 372c488585 | ||
|   | 738b8ff1ee | ||
|   | 1561fc5994 | ||
|   | c84f18545e | ||
|   | 48e4dc75f4 | ||
|   | 63a8d556e5 | ||
|   | e5591618ee | ||
|   | 4794748c73 | ||
|   | 02e7e3b971 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | d2aca3c28b | ||
|   | 11b84a04b3 | ||
|   | f243ce66e7 | ||
|   | baf9b65801 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | 55419d2524 | ||
|   | 401d0b1298 | ||
|   | fce7dc0f4e | ||
|   | 35489ef5b7 | ||
|   | 546d494587 | ||
|   | e8afa2c940 | ||
|   | c1ef1bf605 | ||
|   | 4ab0dbe7e3 | ||
|   | 44f86a94f4 | ||
|   | a0278154a3 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | 8b7e6b200e | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | d6f6c26725 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | cf66343b31 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | d53689332f | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | 4105237027 | ||
| ![greenkeeper[bot]](/assets/img/avatar_default.png)  | 436962e4b8 | ||
|   | a85efa1392 | ||
|   | f0115a5e21 | ||
|   | 80105239dc | ||
|   | baad11288a | ||
|   | 7e50646ede | ||
|   | d4b8e47bcb | ||
|   | 0eefd2922c | ||
|   | 30c0f98691 | ||
|   | 06a7c2e138 | ||
|   | 3537b3de8e | ||
|   | ed6450244d | ||
|   | e813880392 | ||
|   | 9a57efa6d9 | ||
|   | 03ee5eba3b | ||
|   | 295ea79231 | ||
|   | a5486176c1 | ||
|   | de58325fd0 | ||
|   | 1e7932d9c7 | ||
|   | 8ba76df409 | ||
|   | a8f9d20229 | ||
|   | 5e6d1b9ae8 | ||
|   | c5afbaef35 | ||
|   | 3b5a36a09f | ||
|   | fcb20d05d7 | ||
|   | 9e6990c44b | ||
|   | 8f3fd9b0dc | ||
|   | 5b1b4a02d8 | ||
|   | 31de530497 | ||
|   | 16b6b1f2b3 | ||
|   | dba83aa50d | ||
|   | bade054a6a | ||
|   | 34d3485dc9 | ||
|   | a84d066daa | ||
|   | 3360cf27cd | ||
|   | c1a13af611 | ||
|   | 47274a658b | ||
|   | b194334031 | ||
|   | 4136c4a807 | ||
|   | f1c212fe75 | ||
|   | d08cbff4b7 | ||
|   | 0b774475fa | ||
|   | c4f6195df3 | ||
|   | 192cdbe322 | ||
|   | a2a25eb5f8 | ||
|   | 274cf1af1c | ||
|   | 7d11c8b767 | ||
|   | abef6bafe3 | ||
|   | da237a5e2d | ||
|   | 7e50e03cfb | ||
|   | 89d5df20a5 | ||
|   | c09a2a37fe | ||
|   | b5745877ca | ||
|   | c0ac15cad7 | ||
|   | 90ce09be2e | ||
|   | fd39afb374 | ||
|   | 6e04549a9b | ||
|   | 80e56fddd9 | ||
|   | 4daf9e1180 | ||
|   | f72abc0e47 | ||
|   | 9c177f3df2 | ||
|   | a279b32c93 | ||
|   | 51465ba026 | ||
|   | 6a7bdcc533 | ||
|   | fddb3a5f10 | ||
|   | 643c7abc12 | ||
|   | 5715afd44c | ||
|   | d65c1c420e | ||
|   | 38139ee6c9 | ||
|   | 6b96bd0185 | ||
|   | f2b9863eea | ||
|   | f56adce51f | ||
|   | 35598c8064 | ||
|   | a5e716eb5d | ||
|   | e8073b7484 | ||
|   | d6a5fc20bb | ||
|   | e763d43085 | ||
|   | a6904d5249 | ||
|   | 7bcb91d3ca | ||
|   | fb0c1efa41 | ||
|   | 03d243d444 | ||
|   | b91585d1fe | ||
|   | d1fa318cda | ||
|   | 42decae424 | ||
|   | 78bc7c20ed | ||
|   | e6616bdf57 | ||
|   | 35362ed3c7 | ||
|   | cd0b9a8e3f | ||
|   | 110aadd65c | ||
|   | cefe1f34be | ||
|   | d469e2152c | ||
|   | 35c2d47518 | ||
|   | c00634a2cf | ||
|   | d1835e262d | ||
|   | d0f304f0ce | ||
|   | 154abe06a7 | ||
|   | ac41cd378c | ||
|   | d59afda2c9 | ||
|   | 4d213833e2 | ||
|   | e9214d4330 | ||
|   | 6b41bb95b2 | ||
|   | 36de13d543 | ||
|   | 3893def9f4 | ||
|   | ff76c815b1 | ||
|   | 1b9b8912ae | ||
|   | b91b0d17c3 | ||
|   | 579b61a806 | ||
|   | 1e2b484929 | ||
|   | ab7d4fa2a2 | ||
|   | f30c8b8a47 | ||
|   | 25dd19dd8c | ||
|   | fdaebc6315 | ||
|   | f1a05c214e | ||
|   | 9ad32ffee9 | ||
|   | 70f83ab019 | ||
|   | 07e64631f2 | ||
|   | 498416e2e3 | ||
|   | 87c4f908fe | ||
|   | 27e6eaacde | ||
|   | ada47920ca | ||
|   | f2606d62ff | ||
|   | 35032152b3 | ||
|   | 90b545fd69 | ||
|   | 4f7776d1f9 | ||
|   | 03bd0c4c9e | ||
|   | b8b4991a46 | ||
|   | 8b68c5da37 | ||
|   | f26e641905 | ||
|   | 57669c9c03 | ||
|   | 094d873f2e | ||
|   | 7b42653271 | ||
|   | 6a82e94c54 | ||
|   | 1fa4d0d3f8 | ||
|   | d5818214f3 | ||
|   | 0c63ec8157 | ||
|   | 8317a219a5 | ||
|   | ec652dd0ac | ||
|   | 8e3dd75c85 | ||
|   | 3f4de3b1cc | ||
|   | e0d3fd17ce | ||
|   | 671c7cf06b | ||
|   | 99a2c5b3fa | ||
|   | 0343de95b8 | ||
|   | 13f258308e | ||
|   | c627288bde | ||
|   | 1eef90f6cb | ||
|   | 29476ea3da | ||
|   | 7609741680 | ||
|   | 5df85b5feb | ||
|   | b4a4d784c3 | ||
|   | d715af0620 | ||
|   | fe8c384618 | ||
|   | 47d4de75da | ||
|   | 016c7fd2c4 | ||
|   | 7ca5e33a3a | ||
|   | 436773837b | ||
|   | fccfe19e13 | ||
|   | 18be0d36f3 | ||
|   | 9ea7de3564 | ||
|   | d1dce76e28 | ||
|   | f4bf824e79 | ||
|   | cbf5d4b71d | ||
|   | 61e5cb2041 | ||
|   | 38a6aa26bc | ||
|   | 32942709bf | ||
|   | a0305c4c04 | ||
|   | 74be1c81b1 | ||
|   | e82a44c03d | ||
|   | 1e9eeeb980 | ||
|   | 0c7111b438 | ||
|   | ef74653a4b | ||
|   | b032f78769 | ||
|   | 7a0a8b5d2b | ||
|   | 459b374d61 | ||
|   | cc6af402be | ||
|   | f3eeadcd8f | ||
|   | 5b0b83faa7 | ||
|   | 5f289e4767 | ||
|   | a36d73cb52 | ||
|   | 9e319006f3 | ||
|   | 7b8a2aef0f | ||
|   | 4fe2f29478 | ||
|   | 76a25917c0 | ||
|   | df6c9b1a1c | ||
|   | 0ef64a6d0b | ||
|   | 1eb6ad58d5 | ||
|   | 49f8cfb0db | ||
|   | 15a8b4c6e5 | ||
|   | 97d68d7b31 | ||
|   | 4dde54e344 | ||
|   | 3304cc106e | ||
|   | dabda21eb7 | ||
|   | 0a64f638c6 | ||
|   | 3cbdfcb43d | ||
|   | 5734221c8f | ||
|   | b6e33e93de | ||
|   | 77b441f14c | ||
|   | 297019c22c | ||
|   | f5f2215b47 | ||
|   | 904114740b | ||
|   | d2d3f7810e | ||
|   | 2b07b3a873 | ||
|   | d17280b341 | ||
|   | f523d3f3bc | ||
|   | f6e4a1770e | ||
|   | 31006507c0 | ||
|   | 9ca6a6bf06 | ||
|   | afdacf14b7 | ||
|   | 5da18ba535 | ||
|   | e6cc937ac2 | ||
|   | 87091a2e03 | ||
|   | d23bc1e02a | ||
|   | 86fcd9208e | ||
|   | f2b97a889c | ||
|   | 97f91102fe | ||
|   | 07b04578c8 | ||
|   | 31f3c1996b | ||
|   | f4116e7300 | ||
|   | 5e5239c16e | ||
|   | 3adfcd1d13 | ||
|   | 3eb43a5413 | ||
|   | 80f41e2ac1 | ||
|   | 9e0b0b4210 | ||
|   | f3380d3184 | ||
|   | 54bc91ea2b | ||
|   | 59d67d3140 | ||
|   | 7b4c307c46 | ||
|   | 92484be87f | ||
|   | 56b8f8b07d | ||
|   | 722de35037 | ||
|   | d93f76c1af | ||
|   | cba0dd5e17 | ||
|   | 7bb25917f8 | ||
|   | a2e2d5ba77 | ||
|   | 61e05cb50e | ||
|   | 49e82adc6c | ||
|   | e4e668b327 | ||
|   | 8028c85c67 | ||
|   | c5ff6df7e6 | ||
|   | e2b2982f95 | ||
|   | a6e307010f | ||
|   | c636e35467 | ||
|   | 3d26bd0532 | ||
|   | 16130e46dd | ||
|   | 9f703085ba | ||
|   | 0af09f13cf | ||
|   | cd8619113a | ||
|   | 4bf6d9f80b | ||
|   | a559b2c20c | ||
|   | 72411abfcd | ||
|   | 491c3f1dc0 | ||
|   | d2ffc4df6c | 
| @@ -7,27 +7,51 @@ maintainer: | ||||
|   repository_url: https://github.com/syuilo/misskey # Repository URL | ||||
|   feedback_url: https://github.com/syuilo/misskey/issues # Feedback URL (e.g. github issue) | ||||
|  | ||||
| # URL and Port settings overview | ||||
| # e.g., If you want to realize following structure: | ||||
| # | ||||
| #               +--- https://example.com:123 ----------+ | ||||
| # +------+      |+-------------+      +---------------+| | ||||
| # | User | ---> || Proxy (123) | ---> | Misskey (456) || | ||||
| # +------+      |+-------------+      +---------------+| | ||||
| #               +--------------------------------------+ | ||||
| # | ||||
| # You need to set 'https://example.com:123' to 'url' prop and | ||||
| # You need to set 456 to 'port' prop. | ||||
| # | ||||
| # In other words, the 'url' prop should be the final accessible URL seen by a user. | ||||
| # 'port' prop is a port that the Misskey server should actually listen | ||||
| # on and it is not necessarily the port that a user accesses. | ||||
|  | ||||
| url: http://localhost/ | ||||
| # Final accessible URL seen by a user. | ||||
| url: https://example.tld/ | ||||
|  | ||||
|  | ||||
| ### Port and TLS settings ###################################### | ||||
| # | ||||
| # Misskey supports two deployment options for public. | ||||
| # | ||||
|  | ||||
| # Option 1: With Reverse Proxy | ||||
| # | ||||
| #                 +----- https://example.tld/ ------------+ | ||||
| #   +------+      |+-------------+      +----------------+| | ||||
| #   | User | ---> || Proxy (443) | ---> | Misskey (3000) || | ||||
| #   +------+      |+-------------+      +----------------+| | ||||
| #                 +---------------------------------------+ | ||||
| # | ||||
| #   You need to setup reverse proxy. (eg. Nginx) | ||||
| #   You do not define 'https' section. | ||||
|  | ||||
| # Option 2: Standalone | ||||
| # | ||||
| #                 +- https://example.tld/ -+ | ||||
| #   +------+      |   +---------------+    | | ||||
| #   | User | ---> |   | Misskey (443) |    | | ||||
| #   +------+      |   +---------------+    | | ||||
| #                 +------------------------+ | ||||
| # | ||||
| #   You need to run Misskey as root. | ||||
| #   You need to set Certificate in 'https' section. | ||||
|  | ||||
| # To use option 1, uncomment below line. | ||||
| # port: 3000    # A port that your Misskey server should listen. | ||||
|  | ||||
| # To use option 2, uncomment below lines. | ||||
| # port: 443 | ||||
| # | ||||
| # https: | ||||
| #   # path for certification | ||||
| #   key: /etc/letsencrypt/live/example.tld/privkey.pem | ||||
| #   cert: /etc/letsencrypt/live/example.tld/fullchain.pem | ||||
|  | ||||
| ################################################################ | ||||
|  | ||||
| # A port that your Misskey server should listen. | ||||
| # This value is not a port to use when accessing with a browser. | ||||
| port: 80 | ||||
|  | ||||
| mongodb: | ||||
|   host: localhost | ||||
| @@ -98,12 +122,6 @@ drive: | ||||
| # Below settings are optional | ||||
| # | ||||
|  | ||||
| # TLS | ||||
| # https: | ||||
| #   # path for certification | ||||
| #   key: example-tls-key | ||||
| #   cert: example-tls-cert | ||||
|  | ||||
| # Elasticsearch | ||||
| # elasticsearch: | ||||
| #   host: localhost | ||||
| @@ -141,3 +159,10 @@ drive: | ||||
|  | ||||
| # Summaly proxy | ||||
| # summalyProxy: "http://example.com" | ||||
|  | ||||
| # User recommendation | ||||
| user_recommendation: | ||||
|   external: true | ||||
|   engine: http://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}} | ||||
|   timeout: 300000 | ||||
|  | ||||
|   | ||||
							
								
								
									
										88
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -5,6 +5,94 @@ ChangeLog | ||||
|  | ||||
| This document describes breaking changes only. | ||||
|  | ||||
| 10.0.0 | ||||
| ------ | ||||
|  | ||||
| ストリーミングAPIに破壊的変更があります。運営者がすべきことはありません。 | ||||
|  | ||||
| 変更は以下の通りです | ||||
|  | ||||
| * ストリーミングでやり取りする際の snake_case が全て camelCase に | ||||
| * リバーシのストリームエンドポイント名が reversi → gamesReversi、reversiGame → gamesReversiGame に | ||||
| * ストリーミングの個々のエンドポイントが廃止され、一旦元となるストリームに接続してから、個々のチャンネル(今までのエンドポイント)に接続します。詳細は後述します。 | ||||
| * ストリームから流れてくる、キャプチャした投稿の更新イベントに投稿自体のデータは含まれず、代わりにアクションが設定されるようになります。詳細は後述します。 | ||||
| * ストリームに接続する際に追加で指定していたパラメータ(トークン除く)が、URLにクエリとして含むのではなくチャンネル接続時にパラメータ指定するように | ||||
|  | ||||
| ### 個々のエンドポイントが廃止されることによる新しいストリーミングAPIの利用方法 | ||||
| 具体的には、まず https://example.misskey/streaming にwebsocket接続します。 | ||||
| 次に、例えば「messaging」ストリーム(チャンネルと呼びます)に接続したいときは、ストリームに次のようなデータを送信します: | ||||
| ``` javascript | ||||
| { | ||||
|   type: 'connect', | ||||
|   body: { | ||||
|     channel: 'messaging', | ||||
|     id: 'foobar', | ||||
|     params: { | ||||
|       otherparty: 'xxxxxxxxxxxx' | ||||
|     } | ||||
|   } | ||||
| } | ||||
| ``` | ||||
| ここで、`id`にはそのチャンネルとやり取りするための任意のIDを設定します。 | ||||
| IDはチャンネルごとではなく「チャンネルの接続ごと」です。なぜなら、同じチャンネルに異なるパラメータで複数接続するケースもあるからです。 | ||||
| `params`はチャンネルに接続する際のパラメータです。チャンネルによって接続時に必要とされるパラメータは異なります。パラメータ不要のチャンネルに接続する際は、このプロパティは省略可能です。 | ||||
|  | ||||
| チャンネルにメッセージを送信するには、次のようなデータを送信します: | ||||
| ``` javascript | ||||
| { | ||||
|   type: 'channel', | ||||
|   body: { | ||||
|     id: 'foobar', | ||||
|     type: 'something', | ||||
|     body: { | ||||
|       some: 'thing' | ||||
|     } | ||||
|   } | ||||
| } | ||||
| ``` | ||||
| ここで、`id`にはチャンネルに接続するときに指定したIDを設定します。 | ||||
|  | ||||
| 逆に、チャンネルからメッセージが流れてくると、次のようなデータが受信されます: | ||||
| ``` javascript | ||||
| { | ||||
|   type: 'channel', | ||||
|   body: { | ||||
|     id: 'foobar', | ||||
|     type: 'something', | ||||
|     body: { | ||||
|       some: 'thing' | ||||
|     } | ||||
|   } | ||||
| } | ||||
| ``` | ||||
| ここで、`id`にはチャンネルに接続するときに指定したIDが設定されています。 | ||||
|  | ||||
| ### 投稿のキャプチャに関する変更 | ||||
| 投稿の更新イベントに投稿情報は含まれなくなりました。代わりに、その投稿が「リアクションされた」「アンケートに投票された」「削除された」といったアクション情報が設定されます。 | ||||
|  | ||||
| 具体的には次のようなデータが受信されます: | ||||
| ``` javascript | ||||
| { | ||||
|   type: 'noteUpdated', | ||||
|   body: { | ||||
|     id: 'xxxxxxxxxxx', | ||||
|     type: 'reacted', | ||||
|     body: { | ||||
|       reaction: 'hmm' | ||||
|     } | ||||
|   } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| * reacted ... 投稿にリアクションされた。`reaction`プロパティにリアクションコードが含まれます。 | ||||
| * pollVoted ... アンケートに投票された。`choice`プロパティに選択肢ID、`userId`に投票者IDが含まれます。 | ||||
|  | ||||
| 9.0.0 | ||||
| ----- | ||||
|  | ||||
| Misskey v8.64.0 を使っている方は、9.0.0に際しては特にすべきことはありません。 | ||||
| Misskey v8.64.0 に満たないバージョンをお使いの方は、一旦8.64.0にアップデートして(そして起動して)から9.0.0に再度アップデートしてください。 | ||||
|  | ||||
| 8.0.0 | ||||
| ----- | ||||
|  | ||||
|   | ||||
							
								
								
									
										14
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								README.md
									
									
									
									
									
								
							| @@ -71,19 +71,21 @@ Please see [Contribution guide](./CONTRIBUTING.md). | ||||
| ---------------------------------------------------------------- | ||||
| <!-- PATREON_START --> | ||||
| <table><tr> | ||||
| <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"></td> | ||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12731202/0995c46cdcb54153ab5f073f5869b70a/1?token-time=2145916800&token-hash=Yd60FK_SWfQO56SeiJpy1tDHOnCV4xdEywQe8gn5_Wo%3D" alt="negao"></td> | ||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13099460/43cecdbaa63a40d79bf50a96b9910b9d/1?token-time=2145916800&token-hash=d6P5MWHHsCMxUuBAEPAoVc5wLUR19mIhqAq7Ma9h9rI%3D" alt="ne_moni"></td> | ||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12913507/f7181eacafe8469a93033d85f5969c29/1?token-time=2145916800&token-hash=f03BFb4S2FUx9YEt87TnEmifb4h33OywGBW2akQVtQY%3D" alt="Melilot"></td> | ||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12999811/5f349fafcce44dd1824a8b1ebbec4564/2?token-time=2145916800&token-hash=rwZ8qvbm_kpA4ib3kc07tVKupXeySpY5ATQFGxfL9v0%3D" alt="Axella"></td> | ||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12913507/f7181eacafe8469a93033d85f5969c29/2?token-time=2145916800&token-hash=mgPdX9TqZxEg4TTPuc477dxhIgYk9246qafjWZEqZ7g%3D" alt="Melilot"></td> | ||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12999811/5f349fafcce44dd1824a8b1ebbec4564/2?token-time=2145916800&token-hash=rwZ8qvbm_kpA4ib3kc07tVKupXeySpY5ATQFGxfL9v0%3D" alt="Xeltica"></td> | ||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/3384329/8b713330cb27404ea6e9fac50ff96efe/1?token-time=2145916800&token-hash=0eu4-m1gTWA9PhptVZt6rdKcusqcD7RB87rJT23VVFI%3D" alt="べすれい"></td> | ||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12021162/963128bb8d14476dbd8407943db8f31a/1?token-time=2145916800&token-hash=GgJ_NmUB6_nnRNLVGUWjV-WX91On7BOu59LKncYV9fE%3D" alt="gutfuckllc"></td> | ||||
| <td><img src="https://c8.patreon.com/2/100/12718187" alt="Peter G."></td> | ||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13039004/509d0c412eb14ae08d6a812a3054f7d6/1?token-time=2145916800&token-hash=zwSu01tOtn5xTUucDZHuPsCxF2HBEMVs9ROJKTlEV_o%3D" alt="nemu"></td> | ||||
| </tr><tr> | ||||
| <td><a href="https://www.patreon.com/user?u=12731202">negao</a></td> | ||||
| <td><a href="https://www.patreon.com/mastodon">Gargron</a></td> | ||||
| <td><a href="https://www.patreon.com/negao">negao</a></td> | ||||
| <td><a href="https://www.patreon.com/user?u=13099460">ne_moni</a></td> | ||||
| <td><a href="https://www.patreon.com/user?u=12913507">Melilot</a></td> | ||||
| <td><a href="https://www.patreon.com/AxellaMC">Axella</a></td> | ||||
| <td><a href="https://www.patreon.com/AxellaMC">Xeltica</a></td> | ||||
| <td><a href="https://www.patreon.com/user?u=3384329">べすれい</a></td> | ||||
| <td><a href="https://www.patreon.com/gutfuckllc">gutfuckllc</a></td> | ||||
| <td><a href="https://www.patreon.com/user?u=12718187">Peter G.</a></td> | ||||
| @@ -91,19 +93,17 @@ Please see [Contribution guide](./CONTRIBUTING.md). | ||||
| </tr></table> | ||||
| <table><tr> | ||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/5881381/6235ca5d3fb04c8e95ef5b4ff2abcc18/2?token-time=2145916800&token-hash=zElv7ZcPL3viGsXbNG_KWiKrbV0vvw1gk0panx8DJoo%3D" alt="Naoki Kosaka"></td> | ||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12931605/ead494101f364dffa90efe49e36fb494/1?token-time=2145916800&token-hash=NzSFPjIlodXyv41rwK61aZWVZWfI4surJaNj8vWKvqM%3D" alt="Reiju"></td> | ||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13034746/c711c7f58e204ecfbc2fd646bc8a4eee/1?token-time=2145916800&token-hash=UERBN4OyP7Nh5XwwdDg0N0IE5cD6_qUQMO81Z5Wizso%3D" alt="Hiratake"></td> | ||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/4503830/ccf2cc867ea64de0b524bb2e24b9a1cb/1?token-time=2145916800&token-hash=S1zP0QyLU52Dqq6dtc9qNYyWfW86XrYHiR4NMbeOrnA%3D" alt="dansup"></td> | ||||
| <td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12531784/93a45137841849329ba692da92ac7c60/1?token-time=2145916800&token-hash=tMosUojzUYJCH_3t--tvYA-SMCyrS__hzSndyaRSnbo%3D" alt="Takashi Shibuya"></td> | ||||
| </tr><tr> | ||||
| <td><a href="https://www.patreon.com/user?u=5881381">Naoki Kosaka</a></td> | ||||
| <td><a href="https://www.patreon.com/user?u=12931605">Reiju</a></td> | ||||
| <td><a href="https://www.patreon.com/hiratake">Hiratake</a></td> | ||||
| <td><a href="https://www.patreon.com/dansup">dansup</a></td> | ||||
| <td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td> | ||||
| </tr></table> | ||||
|  | ||||
| **Last updated:** Sun, 02 Sep 2018 05:30:06 UTC | ||||
| **Last updated:** Tue, 02 Oct 2018 09:25:07 UTC | ||||
| <!-- PATREON_END --> | ||||
|  | ||||
| :four_leaf_clover: Copyright | ||||
|   | ||||
| @@ -2,7 +2,6 @@ | ||||
|  * Gulp tasks | ||||
|  */ | ||||
|  | ||||
| import * as fs from 'fs'; | ||||
| import * as gulp from 'gulp'; | ||||
| import * as gutil from 'gulp-util'; | ||||
| import * as ts from 'gulp-typescript'; | ||||
| @@ -166,9 +165,7 @@ gulp.task('build:client:pug', [ | ||||
| 			.pipe(pug({ | ||||
| 				locals: { | ||||
| 					themeColor: constants.themeColor, | ||||
| 					facss: fa.dom.css(), | ||||
| 					//hljscss: fs.readFileSync('./node_modules/highlight.js/styles/default.css', 'utf8') | ||||
| 					hljscss: fs.readFileSync('./src/client/assets/code-highlight.css', 'utf8') | ||||
| 					facss: fa.dom.css() | ||||
| 				} | ||||
| 			})) | ||||
| 			.pipe(htmlmin({ | ||||
|   | ||||
| @@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue: | ||||
| common/views/components/media-banner.vue: | ||||
|   sensitive: "閲覧注意" | ||||
|   click-to-show: "クリックして表示" | ||||
| common/views/components/theme.vue: | ||||
|   light-theme: "非ダークモード時に使用するテーマ" | ||||
|   dark-theme: "ダークモード時に使用するテーマ" | ||||
|   light-themes: "明るいテーマ" | ||||
|   dark-themes: "暗いテーマ" | ||||
|   install-a-theme: "テーマのインストール" | ||||
|   theme-code: "テーマコード" | ||||
|   install: "インストール" | ||||
|   installed: "「{}」をインストールしました" | ||||
|   create-a-theme: "テーマの作成" | ||||
|   save-created-theme: "テーマを保存" | ||||
|   primary-color: "プライマリ カラー" | ||||
|   secondary-color: "セカンダリ カラー" | ||||
|   text-color: "文字色" | ||||
|   base-theme: "ベーステーマ" | ||||
|   base-theme-light: "Light" | ||||
|   base-theme-dark: "Dark" | ||||
|   theme-name: "テーマ名" | ||||
|   preview-created-theme: "プレビュー" | ||||
|   invalid-theme: "テーマが正しくありません。" | ||||
|   already-installed: "既にそのテーマはインストールされています。" | ||||
|   saved: "保存しました" | ||||
|   installed-themes: "インストールされたテーマ" | ||||
|   select-theme: "テーマを選択してください" | ||||
|   uninstall: "アンインストール" | ||||
|   uninstalled: "「{}」をアンインストールしました" | ||||
|   author: "作者" | ||||
|   desc: "説明" | ||||
|   export: "エクスポート" | ||||
|   import: "インポート" | ||||
|   import-by-code: "またはコードをペースト" | ||||
|   theme-name-required: "テーマ名は必須です。" | ||||
| common/views/components/cw-button.vue: | ||||
|   hide: "隠す" | ||||
|   show: "もっと見る" | ||||
| @@ -301,6 +333,7 @@ common/views/components/note-menu.vue: | ||||
|   copy-link: "リンクをコピー" | ||||
|   favorite: "お気に入り" | ||||
|   pin: "ピン留め" | ||||
|   unpin: "ピン留め解除" | ||||
|   delete: "削除" | ||||
|   delete-confirm: "この投稿を削除しますか?" | ||||
|   remote: "投稿元で見る" | ||||
| @@ -439,6 +472,7 @@ common/views/pages/follow.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| desktop: | ||||
|   banner-crop-title: "バナーとして表示する部分を選択" | ||||
| @@ -477,13 +511,13 @@ desktop/views/components/charts.vue: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     notes-total: "投稿の積算" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     users-total: "ユーザーの積算" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-total: "ドライブ使用量の積算" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
|     drive-files-total: "ドライブのファイル数の積算" | ||||
|     network-requests: "リクエスト" | ||||
|     network-time: "応答時間" | ||||
|     network-usage: "通信量" | ||||
| @@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| desktop/views/components/followers-window.vue: | ||||
|   followers: "{} のフォロワー" | ||||
| @@ -675,6 +710,7 @@ desktop/views/components/settings.vue: | ||||
|   2fa: "二段階認証" | ||||
|   other: "その他" | ||||
|   license: "ライセンス" | ||||
|   theme: "テーマ" | ||||
|   behaviour: "動作" | ||||
|   fetch-on-scroll: "スクロールで自動読み込み" | ||||
|   fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。" | ||||
| @@ -691,9 +727,10 @@ desktop/views/components/settings.vue: | ||||
|   choose-wallpaper: "壁紙を選択" | ||||
|   delete-wallpaper: "壁紙を削除" | ||||
|   dark-mode: "ダークモード" | ||||
|   use-shadow: "UIに影を使用" | ||||
|   rounded-corners: "UIの角を丸める" | ||||
|   circle-icons: "円形のアイコンを使用" | ||||
|   contrasted-acct: "ユーザー名にコントラストを付ける" | ||||
|   gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用" | ||||
|   post-form-on-timeline: "タイムライン上部に投稿フォームを表示する" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
| @@ -702,7 +739,6 @@ desktop/views/components/settings.vue: | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "マップの自動展開" | ||||
|   show-maps-desc: "位置情報が添付された投稿のマップを自動的に展開します。" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。" | ||||
| @@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| mobile/views/components/friends-maker.vue: | ||||
|   title: "気になるユーザーをフォロー" | ||||
| @@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue: | ||||
|   notification-position: "通知の表示" | ||||
|   notification-position-bottom: "下" | ||||
|   notification-position-top: "上" | ||||
|   theme: "テーマ" | ||||
|   behavior: "動作" | ||||
|   fetch-on-scroll: "スクロールで自動読み込み" | ||||
|   note-visibility: "投稿の公開範囲" | ||||
|   | ||||
| @@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue: | ||||
| common/views/components/media-banner.vue: | ||||
|   sensitive: "閲覧注意" | ||||
|   click-to-show: "クリックして表示" | ||||
| common/views/components/theme.vue: | ||||
|   light-theme: "非ダークモード時に使用するテーマ" | ||||
|   dark-theme: "ダークモード時に使用するテーマ" | ||||
|   light-themes: "明るいテーマ" | ||||
|   dark-themes: "暗いテーマ" | ||||
|   install-a-theme: "テーマのインストール" | ||||
|   theme-code: "テーマコード" | ||||
|   install: "インストール" | ||||
|   installed: "「{}」をインストールしました" | ||||
|   create-a-theme: "テーマの作成" | ||||
|   save-created-theme: "テーマを保存" | ||||
|   primary-color: "プライマリ カラー" | ||||
|   secondary-color: "セカンダリ カラー" | ||||
|   text-color: "文字色" | ||||
|   base-theme: "ベーステーマ" | ||||
|   base-theme-light: "Light" | ||||
|   base-theme-dark: "Dark" | ||||
|   theme-name: "テーマ名" | ||||
|   preview-created-theme: "プレビュー" | ||||
|   invalid-theme: "テーマが正しくありません。" | ||||
|   already-installed: "既にそのテーマはインストールされています。" | ||||
|   saved: "保存しました" | ||||
|   installed-themes: "インストールされたテーマ" | ||||
|   select-theme: "テーマを選択してください" | ||||
|   uninstall: "アンインストール" | ||||
|   uninstalled: "「{}」をアンインストールしました" | ||||
|   author: "作者" | ||||
|   desc: "説明" | ||||
|   export: "エクスポート" | ||||
|   import: "インポート" | ||||
|   import-by-code: "またはコードをペースト" | ||||
|   theme-name-required: "テーマ名は必須です。" | ||||
| common/views/components/cw-button.vue: | ||||
|   hide: "隠す" | ||||
|   show: "もっと見る" | ||||
| @@ -301,6 +333,7 @@ common/views/components/note-menu.vue: | ||||
|   copy-link: "リンクをコピー" | ||||
|   favorite: "Diese Anmerkung favorisieren" | ||||
|   pin: "An die Profilseite pinnen" | ||||
|   unpin: "ピン留め解除" | ||||
|   delete: "Löschen" | ||||
|   delete-confirm: "Diesen Post löschen?" | ||||
|   remote: "Auf Quelle anzeigen" | ||||
| @@ -439,6 +472,7 @@ common/views/pages/follow.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| desktop: | ||||
|   banner-crop-title: "バナーとして表示する部分を選択" | ||||
| @@ -477,13 +511,13 @@ desktop/views/components/charts.vue: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     notes-total: "投稿の積算" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     users-total: "ユーザーの積算" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-total: "ドライブ使用量の積算" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
|     drive-files-total: "ドライブのファイル数の積算" | ||||
|     network-requests: "リクエスト" | ||||
|     network-time: "応答時間" | ||||
|     network-usage: "通信量" | ||||
| @@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue: | ||||
|   following: "Folge ich" | ||||
|   follow: "Folgen" | ||||
|   request-pending: "Ausstehend" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "Follower-Anfragen" | ||||
| desktop/views/components/followers-window.vue: | ||||
|   followers: "{} のフォロワー" | ||||
| @@ -675,6 +710,7 @@ desktop/views/components/settings.vue: | ||||
|   2fa: "Zwei-Faktor-Authentifizierung" | ||||
|   other: "Anderes" | ||||
|   license: "Lizenz" | ||||
|   theme: "テーマ" | ||||
|   behaviour: "Verhalten" | ||||
|   fetch-on-scroll: "Aktualisieren beim scrollen" | ||||
|   fetch-on-scroll-desc: "Wenn du runterscrollst empfängt die Seite automatisch zusätzliche Inhalte." | ||||
| @@ -691,9 +727,10 @@ desktop/views/components/settings.vue: | ||||
|   choose-wallpaper: "壁紙を選択" | ||||
|   delete-wallpaper: "壁紙を削除" | ||||
|   dark-mode: "Nacht Modus" | ||||
|   use-shadow: "UIに影を使用" | ||||
|   rounded-corners: "UIの角を丸める" | ||||
|   circle-icons: "Kreisförmige Icons" | ||||
|   contrasted-acct: "ユーザー名にコントラストを付ける" | ||||
|   gradient-window-header: "Übergang in Fensterköpfen" | ||||
|   post-form-on-timeline: "タイムライン上部に投稿フォームを表示する" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
| @@ -702,7 +739,6 @@ desktop/views/components/settings.vue: | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "Karte anzeigen" | ||||
|   show-maps-desc: "Zeige den Standort zu diesem Beitrag automatisch an." | ||||
|   sound: "Ton" | ||||
|   enable-sounds: "Ton aktivieren" | ||||
|   enable-sounds-desc: "Spiel einen Ton ab beim Erhalten eines Beitrags bzw. einer Nachricht. Diese Einstellung wird im Browser gespeichert." | ||||
| @@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| mobile/views/components/friends-maker.vue: | ||||
|   title: "気になるユーザーをフォロー" | ||||
| @@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue: | ||||
|   notification-position: "通知の表示" | ||||
|   notification-position-bottom: "下" | ||||
|   notification-position-top: "上" | ||||
|   theme: "テーマ" | ||||
|   behavior: "動作" | ||||
|   fetch-on-scroll: "スクロールで自動読み込み" | ||||
|   note-visibility: "投稿の公開範囲" | ||||
|   | ||||
| @@ -109,7 +109,7 @@ common: | ||||
|   use-contrast-reversi-stones: "Make the stone color clear in reversi" | ||||
|   verified-user: "Verified account" | ||||
|   disable-animated-mfm: "Disable animated texts in a post" | ||||
|   always-show-nsfw: "常に閲覧注意のメディアを表示する" | ||||
|   always-show-nsfw: "Always show NSFW contents" | ||||
|   always-mark-nsfw: "Always post with a warning about media attachment" | ||||
|   show-full-acct: "Do not omit the hostname from the username" | ||||
|   reduce-motion: "Reduce motion in UI" | ||||
| @@ -158,7 +158,7 @@ common: | ||||
|     hashtag: "Hashtag" | ||||
|     global: "Global" | ||||
|     mentions: "Mentions" | ||||
|     direct: "ダイレクト投稿" | ||||
|     direct: "Direct post" | ||||
|     notifications: "Notifications" | ||||
|     list: "Lists" | ||||
|     swap-left: "Move to the left" | ||||
| @@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue: | ||||
| common/views/components/media-banner.vue: | ||||
|   sensitive: "NSFW" | ||||
|   click-to-show: "Click to show" | ||||
| common/views/components/theme.vue: | ||||
|   light-theme: "非ダークモード時に使用するテーマ" | ||||
|   dark-theme: "ダークモード時に使用するテーマ" | ||||
|   light-themes: "明るいテーマ" | ||||
|   dark-themes: "暗いテーマ" | ||||
|   install-a-theme: "テーマのインストール" | ||||
|   theme-code: "テーマコード" | ||||
|   install: "インストール" | ||||
|   installed: "「{}」をインストールしました" | ||||
|   create-a-theme: "テーマの作成" | ||||
|   save-created-theme: "テーマを保存" | ||||
|   primary-color: "プライマリ カラー" | ||||
|   secondary-color: "セカンダリ カラー" | ||||
|   text-color: "文字色" | ||||
|   base-theme: "ベーステーマ" | ||||
|   base-theme-light: "Light" | ||||
|   base-theme-dark: "Dark" | ||||
|   theme-name: "テーマ名" | ||||
|   preview-created-theme: "プレビュー" | ||||
|   invalid-theme: "テーマが正しくありません。" | ||||
|   already-installed: "既にそのテーマはインストールされています。" | ||||
|   saved: "保存しました" | ||||
|   installed-themes: "インストールされたテーマ" | ||||
|   select-theme: "テーマを選択してください" | ||||
|   uninstall: "アンインストール" | ||||
|   uninstalled: "「{}」をアンインストールしました" | ||||
|   author: "作者" | ||||
|   desc: "説明" | ||||
|   export: "エクスポート" | ||||
|   import: "インポート" | ||||
|   import-by-code: "またはコードをペースト" | ||||
|   theme-name-required: "テーマ名は必須です。" | ||||
| common/views/components/cw-button.vue: | ||||
|   hide: "Hide" | ||||
|   show: "See more" | ||||
| @@ -301,6 +333,7 @@ common/views/components/note-menu.vue: | ||||
|   copy-link: "Copy link" | ||||
|   favorite: "Favorite this note" | ||||
|   pin: "Pin to your profile" | ||||
|   unpin: "ピン留め解除" | ||||
|   delete: "Delete" | ||||
|   delete-confirm: "Delete this post?" | ||||
|   remote: "Show original note" | ||||
| @@ -439,6 +472,7 @@ common/views/pages/follow.vue: | ||||
|   following: "Following" | ||||
|   follow: "Follow" | ||||
|   request-pending: "Pending follow request" | ||||
|   follow-processing: "Processing follow" | ||||
|   follow-request: "Follow request" | ||||
| desktop: | ||||
|   banner-crop-title: "Crop the part that appears as a banner" | ||||
| @@ -477,13 +511,13 @@ desktop/views/components/charts.vue: | ||||
|     notes: "The number of posts: increase/decrease (Combined)" | ||||
|     local-notes: "The number of posts: increase/decrease (Local)" | ||||
|     remote-notes: "The number of posts: increase/decrease (Remote)" | ||||
|     notes-total: "The number of posts: cumulative total" | ||||
|     notes-total: "投稿の積算" | ||||
|     users: "The number of users: increase/decrease" | ||||
|     users-total: "The number of users: cumulative total" | ||||
|     users-total: "ユーザーの積算" | ||||
|     drive: "Capacity used as the storage: increase/decrease" | ||||
|     drive-total: "Capacity used as the storage: cumulative total" | ||||
|     drive-total: "ドライブ使用量の積算" | ||||
|     drive-files: "The number of files on the storage: increase/decrease" | ||||
|     drive-files-total: "The number of files on the storage: cumulative total" | ||||
|     drive-files-total: "ドライブのファイル数の積算" | ||||
|     network-requests: "Requests" | ||||
|     network-time: "Response time" | ||||
|     network-usage: "Traffic" | ||||
| @@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue: | ||||
|   following: "Following" | ||||
|   follow: "Follow" | ||||
|   request-pending: "Pending follow request" | ||||
|   follow-processing: "Processing follow" | ||||
|   follow-request: "Follow request" | ||||
| desktop/views/components/followers-window.vue: | ||||
|   followers: "{}'s followers" | ||||
| @@ -675,6 +710,7 @@ desktop/views/components/settings.vue: | ||||
|   2fa: "Two-factor authentication" | ||||
|   other: "Other" | ||||
|   license: "License" | ||||
|   theme: "Theme" | ||||
|   behaviour: "Behavior" | ||||
|   fetch-on-scroll: "Endless loading on scroll" | ||||
|   fetch-on-scroll-desc: "When you scroll down the page, it automatically fetches additional content." | ||||
| @@ -691,9 +727,10 @@ desktop/views/components/settings.vue: | ||||
|   choose-wallpaper: "Choose a background" | ||||
|   delete-wallpaper: "Remove background" | ||||
|   dark-mode: "Dark Mode" | ||||
|   use-shadow: "UIに影を使用" | ||||
|   rounded-corners: "UIの角を丸める" | ||||
|   circle-icons: "Use circle icons" | ||||
|   contrasted-acct: "Add contrast to username" | ||||
|   gradient-window-header: "Use gradients on window headers" | ||||
|   post-form-on-timeline: "Display post form at the top of the timeline" | ||||
|   suggest-recent-hashtags: "Show recent popular hashtags on the post form" | ||||
|   show-clock-on-header: "Show clock on upper-right" | ||||
| @@ -702,7 +739,6 @@ desktop/views/components/settings.vue: | ||||
|   show-renoted-my-notes: "Show renoted my posts in timelines" | ||||
|   show-local-renotes: "Show renoted local posts in timelines" | ||||
|   show-maps: "Display a map to show the location" | ||||
|   show-maps-desc: "If there comes a post contains location information, show a map to display the location." | ||||
|   sound: "Sound" | ||||
|   enable-sounds: "Enable sound" | ||||
|   enable-sounds-desc: "Play a sound when you receive a post/message. This setting is stored in the browser." | ||||
| @@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue: | ||||
|   following: "Following" | ||||
|   follow: "Follow" | ||||
|   request-pending: "Pending follow request" | ||||
|   follow-processing: "Processing follow" | ||||
|   follow-request: "Follow request" | ||||
| mobile/views/components/friends-maker.vue: | ||||
|   title: "Let's follow them" | ||||
| @@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue: | ||||
|   notification-position: "Notification style" | ||||
|   notification-position-bottom: "Bottom" | ||||
|   notification-position-top: "Top" | ||||
|   theme: "Theme" | ||||
|   behavior: "Behavior" | ||||
|   fetch-on-scroll: "Endless loading on scroll" | ||||
|   note-visibility: "Post visibility" | ||||
|   | ||||
| @@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue: | ||||
| common/views/components/media-banner.vue: | ||||
|   sensitive: "閲覧注意" | ||||
|   click-to-show: "クリックして表示" | ||||
| common/views/components/theme.vue: | ||||
|   light-theme: "非ダークモード時に使用するテーマ" | ||||
|   dark-theme: "ダークモード時に使用するテーマ" | ||||
|   light-themes: "明るいテーマ" | ||||
|   dark-themes: "暗いテーマ" | ||||
|   install-a-theme: "テーマのインストール" | ||||
|   theme-code: "テーマコード" | ||||
|   install: "インストール" | ||||
|   installed: "「{}」をインストールしました" | ||||
|   create-a-theme: "テーマの作成" | ||||
|   save-created-theme: "テーマを保存" | ||||
|   primary-color: "プライマリ カラー" | ||||
|   secondary-color: "セカンダリ カラー" | ||||
|   text-color: "文字色" | ||||
|   base-theme: "ベーステーマ" | ||||
|   base-theme-light: "Light" | ||||
|   base-theme-dark: "Dark" | ||||
|   theme-name: "テーマ名" | ||||
|   preview-created-theme: "プレビュー" | ||||
|   invalid-theme: "テーマが正しくありません。" | ||||
|   already-installed: "既にそのテーマはインストールされています。" | ||||
|   saved: "保存しました" | ||||
|   installed-themes: "インストールされたテーマ" | ||||
|   select-theme: "テーマを選択してください" | ||||
|   uninstall: "アンインストール" | ||||
|   uninstalled: "「{}」をアンインストールしました" | ||||
|   author: "作者" | ||||
|   desc: "説明" | ||||
|   export: "エクスポート" | ||||
|   import: "インポート" | ||||
|   import-by-code: "またはコードをペースト" | ||||
|   theme-name-required: "テーマ名は必須です。" | ||||
| common/views/components/cw-button.vue: | ||||
|   hide: "隠す" | ||||
|   show: "もっと見る" | ||||
| @@ -301,6 +333,7 @@ common/views/components/note-menu.vue: | ||||
|   copy-link: "Copiar enlace" | ||||
|   favorite: "Me gusta esta nota" | ||||
|   pin: "Fijar en el perfil" | ||||
|   unpin: "ピン留め解除" | ||||
|   delete: "Borrar" | ||||
|   delete-confirm: "¿Seguro que quieres borrar la publicación?" | ||||
|   remote: "Ver el original" | ||||
| @@ -439,6 +472,7 @@ common/views/pages/follow.vue: | ||||
|   following: "Siguiendo" | ||||
|   follow: "Seguir" | ||||
|   request-pending: "Solicitud pendiente" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "Solicitar suscripción" | ||||
| desktop: | ||||
|   banner-crop-title: "Corta la parte que aparece como un banner" | ||||
| @@ -477,13 +511,13 @@ desktop/views/components/charts.vue: | ||||
|     notes: "Número de publicaciones: aumentar/disminuir (Combinado)" | ||||
|     local-notes: "Número de publicaciones: aumentar/disminuir (Local)" | ||||
|     remote-notes: "Número de publicaciones: aumentar/disminuir (Remoto)" | ||||
|     notes-total: "Número de publicaciones: Acumulativo total" | ||||
|     notes-total: "投稿の積算" | ||||
|     users: "Número de usuarios: aumentar/disminuir" | ||||
|     users-total: "Número de usuarios: Acumulativo total" | ||||
|     users-total: "ユーザーの積算" | ||||
|     drive: "Capacidad de almacenamiento usada: aumentar/disminuir" | ||||
|     drive-total: "Capacidad de almacenamiento usada: Acumulativa total" | ||||
|     drive-total: "ドライブ使用量の積算" | ||||
|     drive-files: "Número de archivos almacenados: aumentar/disminuir" | ||||
|     drive-files-total: "Número de archivos almacenados: Acumulativo total" | ||||
|     drive-files-total: "ドライブのファイル数の積算" | ||||
|     network-requests: "リクエスト" | ||||
|     network-time: "応答時間" | ||||
|     network-usage: "通信量" | ||||
| @@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue: | ||||
|   following: "Siguiendo" | ||||
|   follow: "Sigue" | ||||
|   request-pending: "Pendiente de aprobación" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "Solicitud de seguir" | ||||
| desktop/views/components/followers-window.vue: | ||||
|   followers: "{} seguidores" | ||||
| @@ -675,6 +710,7 @@ desktop/views/components/settings.vue: | ||||
|   2fa: "Autenticación de Doble-Factor" | ||||
|   other: "Otros" | ||||
|   license: "Licencia" | ||||
|   theme: "テーマ" | ||||
|   behaviour: "Acciones" | ||||
|   fetch-on-scroll: "Desplazamiento infinito" | ||||
|   fetch-on-scroll-desc: "Cuando te deslizas al final de la página nuevo contenido se carga automáticamente." | ||||
| @@ -691,9 +727,10 @@ desktop/views/components/settings.vue: | ||||
|   choose-wallpaper: "Elije un fondo" | ||||
|   delete-wallpaper: "Suprimir fondo" | ||||
|   dark-mode: "Modo Nocturno" | ||||
|   use-shadow: "UIに影を使用" | ||||
|   rounded-corners: "UIの角を丸める" | ||||
|   circle-icons: "Usar iconos circulares" | ||||
|   contrasted-acct: "ユーザー名にコントラストを付ける" | ||||
|   gradient-window-header: "Usar degradados en las cabeceras de las páginas" | ||||
|   post-form-on-timeline: "Mostrar el formulario de las entradas encima de la línea de tiempo" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
| @@ -702,7 +739,6 @@ desktop/views/components/settings.vue: | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "マップの自動展開" | ||||
|   show-maps-desc: "位置情報が添付された投稿のマップを自動的に展開します。" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。" | ||||
| @@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| mobile/views/components/friends-maker.vue: | ||||
|   title: "気になるユーザーをフォロー" | ||||
| @@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue: | ||||
|   notification-position: "通知の表示" | ||||
|   notification-position-bottom: "下" | ||||
|   notification-position-top: "上" | ||||
|   theme: "テーマ" | ||||
|   behavior: "動作" | ||||
|   fetch-on-scroll: "スクロールで自動読み込み" | ||||
|   note-visibility: "投稿の公開範囲" | ||||
|   | ||||
| @@ -9,7 +9,7 @@ common: | ||||
|   intro: | ||||
|     title: "C’est quoi Misskey ?" | ||||
|     about: "Misskeyはオープンソースの<b>分散型マイクロブログSNS</b>です。リッチで高度にカスタマイズできるUI、投稿へのリアクション、ファイルを一元管理できるドライブなど、先進的な機能を揃えています。また、Fediverseと呼ばれるネットワークに接続できるため、他のSNSともやり取りできます。例えば、あなたが何か投稿すると、その投稿はMisskeyだけでなく他のSNSにも伝わります。ちょうどある惑星から他の惑星に電波を発信している様子をイメージしてください。" | ||||
|     features: "Fonctionnalités" | ||||
|     features: "Options" | ||||
|     rich-contents: "Notes" | ||||
|     rich-contents-desc: "自分の考え、話題の出来事、皆と共有したいことについて発信してください。必要であれば、様々な構文を使って投稿を装飾したり、好きな画像、動画などのファイルやアンケートを添付することもできます。" | ||||
|     reaction: "Réactions" | ||||
| @@ -32,7 +32,7 @@ common: | ||||
|     paragraph2: "Vous pouvez changer l'affichage en <strong>cliquant droit</strong> sur certains widgets." | ||||
|     paragraph3: "Pour supprimer un widget, <strong>glissez et déposez le widget sur la zone étiquetée « Corbeille »</strong> dans l'en-tête." | ||||
|     paragraph4: "Pour terminer la personnalisation, cliquez sur \"Terminer\" dans le coin supérieur droit." | ||||
|     gotit: "Compris!" | ||||
|     gotit: "Compris !" | ||||
|   notification: | ||||
|     file-uploaded: "Le fichier a été téléversé !" | ||||
|     message-from: "Message de {} :" | ||||
| @@ -52,7 +52,7 @@ common: | ||||
|     weeks_ago: "Il y a {} semaines·s" | ||||
|     months_ago: "Il y a {} mois" | ||||
|     years_ago: "Il y a {} an·s" | ||||
|   month-and-day: "{month}/{day}" | ||||
|   month-and-day: "{month} mois/{day} jour" | ||||
|   trash: "Corbeille" | ||||
|   weekday-short: | ||||
|     sunday: "D" | ||||
| @@ -111,7 +111,7 @@ common: | ||||
|   disable-animated-mfm: "Désactiver les textes animés dans les publications" | ||||
|   always-show-nsfw: "常に閲覧注意のメディアを表示する" | ||||
|   always-mark-nsfw: "常にメディアを閲覧注意として投稿" | ||||
|   show-full-acct: "ユーザー名のホストを省略しない" | ||||
|   show-full-acct: "Afficher l’adresse complète de l’utilisateur" | ||||
|   reduce-motion: "Réduire les animations dans l’interface utilisateur" | ||||
|   this-setting-is-this-device-only: "Uniquement sur cet appareil" | ||||
|   do-not-use-in-production: 'Il s’agit d’une version de développement. Ne pas utiliser dans un environnement de production.' | ||||
| @@ -149,16 +149,16 @@ common: | ||||
|     donation: "Dons" | ||||
|     nav: "Navigation" | ||||
|     tips: "Conseils" | ||||
|     hashtags: "Étiquettes" | ||||
|     hashtags: "Hashtags" | ||||
|   deck: | ||||
|     widgets: "Widgets" | ||||
|     home: "Accueil" | ||||
|     local: "Local" | ||||
|     hybrid: "Social" | ||||
|     hashtag: "ハッシュタグ" | ||||
|     hashtag: "Hashtag" | ||||
|     global: "Global" | ||||
|     mentions: "Mentions" | ||||
|     direct: "ダイレクト投稿" | ||||
|     direct: "Messages directs" | ||||
|     notifications: "Notifications" | ||||
|     list: "Liste" | ||||
|     swap-left: "Déplacer à gauche" | ||||
| @@ -189,7 +189,7 @@ auth/views/index.vue: | ||||
|   denied: "L'autorisation de l'application a été refusée." | ||||
|   denied-paragraph: "Cette application ne va pas accéder à votre compte." | ||||
|   already-authorized: "Cette application est déjà autorisée" | ||||
|   allowed: "アプリケーションの連携を許可しました" | ||||
|   allowed: "Permissions autorisées de l’application." | ||||
|   callback-url: "Retour vers l'application" | ||||
|   please-go-back: "Veillez retourner à l'application." | ||||
|   error: "La session n'existe pas." | ||||
| @@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue: | ||||
| common/views/components/media-banner.vue: | ||||
|   sensitive: "Contenu sensible" | ||||
|   click-to-show: "Cliquer pour afficher" | ||||
| common/views/components/theme.vue: | ||||
|   light-theme: "非ダークモード時に使用するテーマ" | ||||
|   dark-theme: "ダークモード時に使用するテーマ" | ||||
|   light-themes: "明るいテーマ" | ||||
|   dark-themes: "暗いテーマ" | ||||
|   install-a-theme: "Installer un thème" | ||||
|   theme-code: "Code du thème" | ||||
|   install: "Installation" | ||||
|   installed: "« {} » a été installé" | ||||
|   create-a-theme: "Créer un thème" | ||||
|   save-created-theme: "Enregistrer le thème" | ||||
|   primary-color: "Couleur primaire" | ||||
|   secondary-color: "Couleur secondaire" | ||||
|   text-color: "Couleur du texte" | ||||
|   base-theme: "Thème de base" | ||||
|   base-theme-light: "Clair" | ||||
|   base-theme-dark: "Sombre" | ||||
|   theme-name: "Nom du Thème" | ||||
|   preview-created-theme: "Prévisualisation" | ||||
|   invalid-theme: "Thème n’est pas valide." | ||||
|   already-installed: "Le thème est déjà installé." | ||||
|   saved: "enregistré" | ||||
|   installed-themes: "Thèmes installés" | ||||
|   select-theme: "Veuillez sélectionner un thème" | ||||
|   uninstall: "Désinstaller" | ||||
|   uninstalled: "« {} » a été désinstallé" | ||||
|   author: "Auteur" | ||||
|   desc: "Description" | ||||
|   export: "エクスポート" | ||||
|   import: "Importer" | ||||
|   import-by-code: "Ou coller du code" | ||||
|   theme-name-required: "Nom du thème est obligatoire." | ||||
| common/views/components/cw-button.vue: | ||||
|   hide: "Masquer" | ||||
|   show: "Voir plus" | ||||
| @@ -301,6 +333,7 @@ common/views/components/note-menu.vue: | ||||
|   copy-link: "Copier le lien" | ||||
|   favorite: "Mettre cette note en favoris" | ||||
|   pin: "Épingler sur votre profil" | ||||
|   unpin: "Désépingler" | ||||
|   delete: "Supprimer" | ||||
|   delete-confirm: "Supprimer cette publication ?" | ||||
|   remote: "Afficher la note originale" | ||||
| @@ -401,7 +434,7 @@ common/views/widgets/posts-monitor.vue: | ||||
|   title: "Graphe des publications" | ||||
|   toggle: "Basculer entre les vues" | ||||
| common/views/widgets/hashtags.vue: | ||||
|   title: "Étiquettes" | ||||
|   title: "Hashtags" | ||||
| common/views/widgets/server.vue: | ||||
|   title: "Informations sur le serveur" | ||||
|   toggle: "Afficher les vues" | ||||
| @@ -420,7 +453,7 @@ common/views/widgets/tips.vue: | ||||
|   tips-line4: "Vous pouvez coller des images à partir du presse-papier sur la fenêtre de la note" | ||||
|   tips-line5: "Vous pouvez téléverser des fichiers sur le Drive en faisant un glisser-déposer" | ||||
|   tips-line6: "Vous pouvez déplacer un dossier en le glissant dans le Drive" | ||||
|   tips-line7: "ドライブでフォルダをドラッグしてフォルダ移動できます" | ||||
|   tips-line7: "Vous pouvez déplacer des dossiers en les glissant dans le Drive" | ||||
|   tips-line8: "Vous pouvez personnaliser l'Accueil via les paramètres" | ||||
|   tips-line9: "Misskey est sous licence AGPLv3" | ||||
|   tips-line10: "タイムマシンウィジェットを利用すると、簡単に過去のタイムラインに遡れます" | ||||
| @@ -428,7 +461,7 @@ common/views/widgets/tips.vue: | ||||
|   tips-line13: "Tous les fichiers attachés à cette publication sont sauvegardés dans le Drive" | ||||
|   tips-line14: "ホームのカスタマイズ中、ウィジェットを右クリックしてデザインを変更できます" | ||||
|   tips-line17: "Vous pouvez mettre un texte en surbrillance en le mettant entre ** **" | ||||
|   tips-line19: "いくつかのウィンドウはブラウザの外に切り離すことができます" | ||||
|   tips-line19: "Plusieurs fenêtres peuvent être détachées en dehors du navigateur." | ||||
|   tips-line20: "カレンダーウィジェットのパーセンテージは、経過の割合を示しています" | ||||
|   tips-line21: "Vous pouvez aussi utiliser l'API pour développer des Bots." | ||||
|   tips-line23: "Mayu est mignone avec ses sourcils." | ||||
| @@ -439,6 +472,7 @@ common/views/pages/follow.vue: | ||||
|   following: "Suit" | ||||
|   follow: "Suivre" | ||||
|   request-pending: "Demande d'abonnement en attente" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "Demande d'abonnement" | ||||
| desktop: | ||||
|   banner-crop-title: "Découpez la partie qui apparaitra comme bannière" | ||||
| @@ -451,7 +485,7 @@ desktop: | ||||
|   uploading-avatar: "Téléversement du nouvel avatar" | ||||
|   avatar-updated: "L'avatar est mis à jour" | ||||
|   choose-avatar: "Choisir un avatar" | ||||
|   invalid-filetype: "この形式のファイルはサポートされていません" | ||||
|   invalid-filetype: "Ce format de fichier n’est pas pris en charge" | ||||
| desktop/views/components/activity.chart.vue: | ||||
|   total: "Noirs ... Total" | ||||
|   notes: "Bleu ... Notes" | ||||
| @@ -477,13 +511,13 @@ desktop/views/components/charts.vue: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     notes-total: "投稿の積算" | ||||
|     users: "Nombre d’utilisateurs·trices : augmentation/diminution" | ||||
|     users-total: "Nombre total d’utilisateurs·trices : total cumulé" | ||||
|     users-total: "ユーザーの積算" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-total: "ドライブ使用量の積算" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
|     drive-files-total: "ドライブのファイル数の積算" | ||||
|     network-requests: "Requêtes" | ||||
|     network-time: "Temps de réponse" | ||||
|     network-usage: "Traffic" | ||||
| @@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue: | ||||
|   following: "Abonnements" | ||||
|   follow: "Suivre" | ||||
|   request-pending: "En attente d'approbation" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "Demande d'abonnement" | ||||
| desktop/views/components/followers-window.vue: | ||||
|   followers: "{} abonné·e·s" | ||||
| @@ -675,6 +710,7 @@ desktop/views/components/settings.vue: | ||||
|   2fa: "Vérification en deux étapes" | ||||
|   other: "Autres" | ||||
|   license: "License" | ||||
|   theme: "Thèmes" | ||||
|   behaviour: "Comportement" | ||||
|   fetch-on-scroll: "Chargement lors du défilement" | ||||
|   fetch-on-scroll-desc: "Chargement automatique du contenu lors du défilement de la page." | ||||
| @@ -691,18 +727,18 @@ desktop/views/components/settings.vue: | ||||
|   choose-wallpaper: "Sélectionner un fond d'écran" | ||||
|   delete-wallpaper: "Supprimer le fond d'écran" | ||||
|   dark-mode: "Mode nuit" | ||||
|   use-shadow: "Utiliser les ombres dans l'interface utilisateur" | ||||
|   rounded-corners: "Coins arrondis" | ||||
|   circle-icons: "Utiliser des icônes circulaires" | ||||
|   contrasted-acct: "Nom d’utilisateur contrasté" | ||||
|   gradient-window-header: "Utiliser les dégradés sur la barre de titre de la fenêtre" | ||||
|   post-form-on-timeline: "Afficher le formulaire en haut du fil" | ||||
|   suggest-recent-hashtags: "Afficher les hashtags populaires dans le champs de saisie" | ||||
|   show-clock-on-header: "Afficher l'horloge à droite sur le coté supérieur" | ||||
|   show-reply-target: "Afficher les réponses" | ||||
|   show-my-renotes: "Afficher mes republications dans le fil" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
|   show-renoted-my-notes: "Afficher mes republications dans les fils" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "Afficher la carte" | ||||
|   show-maps-desc: "位置情報が添付された投稿のマップを自動的に展開します。" | ||||
|   sound: "Son" | ||||
|   enable-sounds: "Activer le son" | ||||
|   enable-sounds-desc: "Jouer un son lorsque vous recevez un message. Ce paramètre est sauvegardé dans le navigateur." | ||||
| @@ -741,7 +777,7 @@ desktop/views/components/settings.vue: | ||||
|   debug-mode: "Activer le mode debug" | ||||
|   debug-mode-desc: "Ce paramètre est stocké dans le navigateur." | ||||
|   experimental: "Activer les fonctionnalités expérimentales" | ||||
|   experimental-desc: "実験的機能を有効にするとMisskeyの動作が不安定になる可能性があります。この設定はブラウザに記憶されます。" | ||||
|   experimental-desc: "L’activation des fonctionnalités expérimentales peuvent rendre le client Misskey instable. Ce paramètre est stocké dans le navigateur." | ||||
|   tools: "Outils" | ||||
|   task-manager: "Gestionnaire de tâches" | ||||
|   third-parties: "Services tiers" | ||||
| @@ -811,12 +847,12 @@ desktop/views/components/timeline.vue: | ||||
|   hybrid: "Social" | ||||
|   global: "Global" | ||||
|   mentions: "Mentions" | ||||
|   messages: "メッセージ" | ||||
|   messages: "Messages" | ||||
|   list: "Listes" | ||||
|   hashtag: "ハッシュタグ" | ||||
|   add-tag-timeline: "ハッシュタグを追加" | ||||
|   add-list: "リストを追加" | ||||
|   list-name: "リスト名" | ||||
|   hashtag: "Hashtag" | ||||
|   add-tag-timeline: "Ajouter un fil de hashtags" | ||||
|   add-list: "Ajouter une nouvelle liste" | ||||
|   list-name: "Nom de la liste" | ||||
| desktop/views/components/ui.header.vue: | ||||
|   welcome-back: "Content de vous revoir !" | ||||
|   adjective: "さん" | ||||
| @@ -932,7 +968,7 @@ desktop/views/pages/selectdrive.vue: | ||||
|   cancel: "Annuler" | ||||
|   upload: "Uploader un ou plusieurs fichier(s) depuis votre PC" | ||||
| desktop/views/pages/search.vue: | ||||
|   not-available: "検索機能はインスタンスの設定で無効になっています。" | ||||
|   not-available: "La fonction de recherche est désactivée dans les paramètres de l’instance." | ||||
|   not-found: "Aucun message trouvé pour '{}'" | ||||
| desktop/views/pages/share.vue: | ||||
|   share-with: "Partager avec {}" | ||||
| @@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue: | ||||
|   following: "Abonnements" | ||||
|   follow: "Suivre" | ||||
|   request-pending: "En attente d'approbation" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "Demande d'abonnement" | ||||
| mobile/views/components/friends-maker.vue: | ||||
|   title: "Abonnez-vous aux utilisateurs" | ||||
| @@ -1142,7 +1179,7 @@ mobile/views/pages/home.vue: | ||||
|   hybrid: "Social" | ||||
|   global: "Global" | ||||
|   mentions: "Mentions" | ||||
|   messages: "メッセージ" | ||||
|   messages: "Messages" | ||||
| mobile/views/pages/tag.vue: | ||||
|   no-posts-found: "Pas de message avec un hashtag {} trouvé." | ||||
| mobile/views/pages/welcome.vue: | ||||
| @@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue: | ||||
|   notification-position: "Style de notification" | ||||
|   notification-position-bottom: "en bas" | ||||
|   notification-position-top: "en haut" | ||||
|   theme: "Thème" | ||||
|   behavior: "Comportement" | ||||
|   fetch-on-scroll: "Chargement lors du défilement" | ||||
|   note-visibility: "Visibilité de la publication" | ||||
|   | ||||
| @@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue: | ||||
| common/views/components/media-banner.vue: | ||||
|   sensitive: "閲覧注意" | ||||
|   click-to-show: "クリックして表示" | ||||
| common/views/components/theme.vue: | ||||
|   light-theme: "非ダークモード時に使用するテーマ" | ||||
|   dark-theme: "ダークモード時に使用するテーマ" | ||||
|   light-themes: "明るいテーマ" | ||||
|   dark-themes: "暗いテーマ" | ||||
|   install-a-theme: "テーマのインストール" | ||||
|   theme-code: "テーマコード" | ||||
|   install: "インストール" | ||||
|   installed: "「{}」をインストールしました" | ||||
|   create-a-theme: "テーマの作成" | ||||
|   save-created-theme: "テーマを保存" | ||||
|   primary-color: "プライマリ カラー" | ||||
|   secondary-color: "セカンダリ カラー" | ||||
|   text-color: "文字色" | ||||
|   base-theme: "ベーステーマ" | ||||
|   base-theme-light: "Light" | ||||
|   base-theme-dark: "Dark" | ||||
|   theme-name: "テーマ名" | ||||
|   preview-created-theme: "プレビュー" | ||||
|   invalid-theme: "テーマが正しくありません。" | ||||
|   already-installed: "既にそのテーマはインストールされています。" | ||||
|   saved: "保存しました" | ||||
|   installed-themes: "インストールされたテーマ" | ||||
|   select-theme: "テーマを選択してください" | ||||
|   uninstall: "アンインストール" | ||||
|   uninstalled: "「{}」をアンインストールしました" | ||||
|   author: "作者" | ||||
|   desc: "説明" | ||||
|   export: "エクスポート" | ||||
|   import: "インポート" | ||||
|   import-by-code: "またはコードをペースト" | ||||
|   theme-name-required: "テーマ名は必須です。" | ||||
| common/views/components/cw-button.vue: | ||||
|   hide: "隠す" | ||||
|   show: "もっと見る" | ||||
| @@ -301,6 +333,7 @@ common/views/components/note-menu.vue: | ||||
|   copy-link: "リンクをコピー" | ||||
|   favorite: "お気に入り" | ||||
|   pin: "ピン留め" | ||||
|   unpin: "ピン留め解除" | ||||
|   delete: "削除" | ||||
|   delete-confirm: "この投稿を削除しますか?" | ||||
|   remote: "投稿元で見る" | ||||
| @@ -439,6 +472,7 @@ common/views/pages/follow.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| desktop: | ||||
|   banner-crop-title: "バナーとして表示する部分を選択" | ||||
| @@ -477,13 +511,13 @@ desktop/views/components/charts.vue: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     notes-total: "投稿の積算" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     users-total: "ユーザーの積算" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-total: "ドライブ使用量の積算" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
|     drive-files-total: "ドライブのファイル数の積算" | ||||
|     network-requests: "リクエスト" | ||||
|     network-time: "応答時間" | ||||
|     network-usage: "通信量" | ||||
| @@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| desktop/views/components/followers-window.vue: | ||||
|   followers: "{} のフォロワー" | ||||
| @@ -675,6 +710,7 @@ desktop/views/components/settings.vue: | ||||
|   2fa: "二段階認証" | ||||
|   other: "その他" | ||||
|   license: "ライセンス" | ||||
|   theme: "テーマ" | ||||
|   behaviour: "動作" | ||||
|   fetch-on-scroll: "スクロールで自動読み込み" | ||||
|   fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。" | ||||
| @@ -691,9 +727,10 @@ desktop/views/components/settings.vue: | ||||
|   choose-wallpaper: "壁紙を選択" | ||||
|   delete-wallpaper: "壁紙を削除" | ||||
|   dark-mode: "ダークモード" | ||||
|   use-shadow: "UIに影を使用" | ||||
|   rounded-corners: "UIの角を丸める" | ||||
|   circle-icons: "円形のアイコンを使用" | ||||
|   contrasted-acct: "ユーザー名にコントラストを付ける" | ||||
|   gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用" | ||||
|   post-form-on-timeline: "タイムライン上部に投稿フォームを表示する" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
| @@ -702,7 +739,6 @@ desktop/views/components/settings.vue: | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "マップの自動展開" | ||||
|   show-maps-desc: "位置情報が添付された投稿のマップを自動的に展開します。" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。" | ||||
| @@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| mobile/views/components/friends-maker.vue: | ||||
|   title: "気になるユーザーをフォロー" | ||||
| @@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue: | ||||
|   notification-position: "通知の表示" | ||||
|   notification-position-bottom: "下" | ||||
|   notification-position-top: "上" | ||||
|   theme: "テーマ" | ||||
|   behavior: "動作" | ||||
|   fetch-on-scroll: "スクロールで自動読み込み" | ||||
|   note-visibility: "投稿の公開範囲" | ||||
|   | ||||
| @@ -285,6 +285,39 @@ common/views/components/media-banner.vue: | ||||
|   sensitive: "閲覧注意" | ||||
|   click-to-show: "クリックして表示" | ||||
|  | ||||
| common/views/components/theme.vue: | ||||
|   light-theme: "非ダークモード時に使用するテーマ" | ||||
|   dark-theme: "ダークモード時に使用するテーマ" | ||||
|   light-themes: "明るいテーマ" | ||||
|   dark-themes: "暗いテーマ" | ||||
|   install-a-theme: "テーマのインストール" | ||||
|   theme-code: "テーマコード" | ||||
|   install: "インストール" | ||||
|   installed: "「{}」をインストールしました" | ||||
|   create-a-theme: "テーマの作成" | ||||
|   save-created-theme: "テーマを保存" | ||||
|   primary-color: "プライマリ カラー" | ||||
|   secondary-color: "セカンダリ カラー" | ||||
|   text-color: "文字色" | ||||
|   base-theme: "ベーステーマ" | ||||
|   base-theme-light: "Light" | ||||
|   base-theme-dark: "Dark" | ||||
|   theme-name: "テーマ名" | ||||
|   preview-created-theme: "プレビュー" | ||||
|   invalid-theme: "テーマが正しくありません。" | ||||
|   already-installed: "既にそのテーマはインストールされています。" | ||||
|   saved: "保存しました" | ||||
|   installed-themes: "インストールされたテーマ" | ||||
|   select-theme: "テーマを選択してください" | ||||
|   uninstall: "アンインストール" | ||||
|   uninstalled: "「{}」をアンインストールしました" | ||||
|   author: "作者" | ||||
|   desc: "説明" | ||||
|   export: "エクスポート" | ||||
|   import: "インポート" | ||||
|   import-by-code: "またはコードをペースト" | ||||
|   theme-name-required: "テーマ名は必須です。" | ||||
|  | ||||
| common/views/components/cw-button.vue: | ||||
|   hide: "隠す" | ||||
|   show: "もっと見る" | ||||
| @@ -328,6 +361,7 @@ common/views/components/note-menu.vue: | ||||
|   copy-link: "リンクをコピー" | ||||
|   favorite: "お気に入り" | ||||
|   pin: "ピン留め" | ||||
|   unpin: "ピン留め解除" | ||||
|   delete: "削除" | ||||
|   delete-confirm: "この投稿を削除しますか?" | ||||
|   remote: "投稿元で見る" | ||||
| @@ -488,6 +522,7 @@ common/views/pages/follow.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
|  | ||||
| desktop: | ||||
| @@ -531,13 +566,13 @@ desktop/views/components/charts.vue: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     notes-total: "投稿の積算" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     users-total: "ユーザーの積算" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-total: "ドライブ使用量の積算" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
|     drive-files-total: "ドライブのファイル数の積算" | ||||
|     network-requests: "リクエスト" | ||||
|     network-time: "応答時間" | ||||
|     network-usage: "通信量" | ||||
| @@ -630,6 +665,7 @@ desktop/views/components/follow-button.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
|  | ||||
| desktop/views/components/followers-window.vue: | ||||
| @@ -761,6 +797,7 @@ desktop/views/components/settings.vue: | ||||
|   2fa: "二段階認証" | ||||
|   other: "その他" | ||||
|   license: "ライセンス" | ||||
|   theme: "テーマ" | ||||
|  | ||||
|   behaviour: "動作" | ||||
|   fetch-on-scroll: "スクロールで自動読み込み" | ||||
| @@ -783,7 +820,6 @@ desktop/views/components/settings.vue: | ||||
|   rounded-corners: "UIの角を丸める" | ||||
|   circle-icons: "円形のアイコンを使用" | ||||
|   contrasted-acct: "ユーザー名にコントラストを付ける" | ||||
|   gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用" | ||||
|   post-form-on-timeline: "タイムライン上部に投稿フォームを表示する" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
| @@ -792,7 +828,6 @@ desktop/views/components/settings.vue: | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "マップの自動展開" | ||||
|   show-maps-desc: "位置情報が添付された投稿のマップを自動的に展開します。" | ||||
|  | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
| @@ -1207,6 +1242,7 @@ mobile/views/components/follow-button.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
|  | ||||
| mobile/views/components/friends-maker.vue: | ||||
| @@ -1418,6 +1454,7 @@ mobile/views/pages/settings.vue: | ||||
|   notification-position: "通知の表示" | ||||
|   notification-position-bottom: "下" | ||||
|   notification-position-top: "上" | ||||
|   theme: "テーマ" | ||||
|   behavior: "動作" | ||||
|   fetch-on-scroll: "スクロールで自動読み込み" | ||||
|   note-visibility: "投稿の公開範囲" | ||||
|   | ||||
| @@ -264,9 +264,41 @@ common/views/components/connect-failed.troubleshooter.vue: | ||||
| common/views/components/media-banner.vue: | ||||
|   sensitive: "見せたらあかん" | ||||
|   click-to-show: "押してみ、見せたるわ" | ||||
| common/views/components/theme.vue: | ||||
|   light-theme: "非ダークモード時に使用するテーマ" | ||||
|   dark-theme: "ダークモード時に使用するテーマ" | ||||
|   light-themes: "明るいテーマ" | ||||
|   dark-themes: "暗いテーマ" | ||||
|   install-a-theme: "テーマのインストール" | ||||
|   theme-code: "テーマコード" | ||||
|   install: "インストール" | ||||
|   installed: "「{}」をインストールしました" | ||||
|   create-a-theme: "テーマの作成" | ||||
|   save-created-theme: "テーマを保存" | ||||
|   primary-color: "プライマリ カラー" | ||||
|   secondary-color: "セカンダリ カラー" | ||||
|   text-color: "文字色" | ||||
|   base-theme: "ベーステーマ" | ||||
|   base-theme-light: "Light" | ||||
|   base-theme-dark: "Dark" | ||||
|   theme-name: "テーマ名" | ||||
|   preview-created-theme: "プレビュー" | ||||
|   invalid-theme: "テーマが正しくありません。" | ||||
|   already-installed: "既にそのテーマはインストールされています。" | ||||
|   saved: "保存しました" | ||||
|   installed-themes: "インストールされたテーマ" | ||||
|   select-theme: "テーマを選択してください" | ||||
|   uninstall: "アンインストール" | ||||
|   uninstalled: "「{}」をアンインストールしました" | ||||
|   author: "作者" | ||||
|   desc: "説明" | ||||
|   export: "エクスポート" | ||||
|   import: "インポート" | ||||
|   import-by-code: "またはコードをペースト" | ||||
|   theme-name-required: "テーマ名は必須です。" | ||||
| common/views/components/cw-button.vue: | ||||
|   hide: "見せへんわ" | ||||
|   show: "もっとあるやろ!" | ||||
|   hide: "もうええわ" | ||||
|   show: "見たいやろ?" | ||||
| common/views/components/messaging.vue: | ||||
|   search-user: "ユーザーを探す" | ||||
|   you: "あんさん" | ||||
| @@ -301,6 +333,7 @@ common/views/components/note-menu.vue: | ||||
|   copy-link: "リンクをコピー" | ||||
|   favorite: "お気に入り" | ||||
|   pin: "ピン留め" | ||||
|   unpin: "ピン留めやめる" | ||||
|   delete: "ほかす" | ||||
|   delete-confirm: "この投稿を削除してもええか?" | ||||
|   remote: "投稿元に行ってみよか" | ||||
| @@ -431,7 +464,7 @@ common/views/widgets/tips.vue: | ||||
|   tips-line19: "いくつかのウィンドウはブラウザの外に切り離すことができんで" | ||||
|   tips-line20: "カレンダーウィジェットのパーセンテージは、経過の割合を示してんねん" | ||||
|   tips-line21: "APIをつこてbotの開発なども行えるで" | ||||
|   tips-line23: "まゆかわいいよまゆ" | ||||
|   tips-line23: "ウチのタコちゃんかわええやろ…今の突っ込むところや!" | ||||
|   tips-line24: "Misskeyは2014年にサービスを開始したんよ" | ||||
|   tips-line25: "対応ブラウザやったらMisskeyを開いとらんでも通知を受け取れんで" | ||||
| common/views/pages/follow.vue: | ||||
| @@ -439,6 +472,7 @@ common/views/pages/follow.vue: | ||||
|   following: "フォローしとる" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォローの許し待っとる" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー許してくれや!言うてみる" | ||||
| desktop: | ||||
|   banner-crop-title: "どこバナーとして出す?" | ||||
| @@ -453,10 +487,10 @@ desktop: | ||||
|   choose-avatar: "アバターにする画像選んでや" | ||||
|   invalid-filetype: "この形式のファイル無理やねん" | ||||
| desktop/views/components/activity.chart.vue: | ||||
|   total: "Black ... Total" | ||||
|   notes: "Blue ... Notes" | ||||
|   replies: "Red ... Replies" | ||||
|   renotes: "Green ... Renotes" | ||||
|   total: "黒いの… 全部" | ||||
|   notes: "青いの… 投稿" | ||||
|   replies: "赤いの… 返信" | ||||
|   renotes: "みどり… Renotes" | ||||
| desktop/views/components/activity.vue: | ||||
|   title: "アクティビティ" | ||||
|   toggle: "表示変える" | ||||
| @@ -477,13 +511,13 @@ desktop/views/components/charts.vue: | ||||
|     notes: "投稿の増減(統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "全部の投稿" | ||||
|     notes-total: "投稿の積算" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     users-total: "ユーザーの積算" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-total: "ドライブ使用量の積算" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
|     drive-files-total: "ドライブのファイル数の積算" | ||||
|     network-requests: "リクエスト" | ||||
|     network-time: "応答時間" | ||||
|     network-usage: "通信量" | ||||
| @@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue: | ||||
|   following: "フォローしとる" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォローの許し待っとる" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー許してくれや!言うてみる" | ||||
| desktop/views/components/followers-window.vue: | ||||
|   followers: "{} のフォロワー" | ||||
| @@ -588,7 +623,7 @@ desktop/views/components/home.vue: | ||||
|   add: "増やす" | ||||
| desktop/views/input-dialog.vue: | ||||
|   cancel: "やめとくわ" | ||||
|   ok: "決定" | ||||
|   ok: "これや!" | ||||
| desktop/views/components/messaging-room-window.vue: | ||||
|   title: "メッセージ:" | ||||
| desktop/views/components/messaging-window.vue: | ||||
| @@ -675,6 +710,7 @@ desktop/views/components/settings.vue: | ||||
|   2fa: "二段階認証" | ||||
|   other: "その他" | ||||
|   license: "ライセンス" | ||||
|   theme: "テーマ" | ||||
|   behaviour: "動き" | ||||
|   fetch-on-scroll: "スクロールしたらもっと見せてや" | ||||
|   fetch-on-scroll-desc: "ページを下までスクロールしたときに自動でもっとコンテンツを読み込むで。" | ||||
| @@ -691,9 +727,10 @@ desktop/views/components/settings.vue: | ||||
|   choose-wallpaper: "壁紙選ぶ" | ||||
|   delete-wallpaper: "壁紙ほかす" | ||||
|   dark-mode: "夜にすんで" | ||||
|   use-shadow: "UIに影付けたる" | ||||
|   rounded-corners: "みんなまぁるくUI変更" | ||||
|   circle-icons: "アイコンもタコ焼きも丸いやんな?" | ||||
|   contrasted-acct: "ユーザー名ようわからんし見やすしといて" | ||||
|   gradient-window-header: "ウィンドウのタイトルバーにグラデーション付ける" | ||||
|   post-form-on-timeline: "タイムラインの上の方で投稿できるようにせえへん?" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示すんで" | ||||
|   show-clock-on-header: "右上をカリヨン広場にする(時計表示)" | ||||
| @@ -702,7 +739,6 @@ desktop/views/components/settings.vue: | ||||
|   show-renoted-my-notes: "わしのRenoteもタイムライン載せてくれや" | ||||
|   show-local-renotes: "ローカル投稿のRenoteも見たいんや" | ||||
|   show-maps: "地図勝手にバァーって開いてくれ" | ||||
|   show-maps-desc: "どこにおるんかわかっとる投稿の地図は自動で見せるで" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンド鳴らす" | ||||
|   enable-sounds-desc: "投稿やメッセージもろたとき、音鳴らしたるわ。大丈夫や、この設定はブラウザが覚えてくれとる。" | ||||
| @@ -793,7 +829,7 @@ desktop/views/components/settings.profile.vue: | ||||
|   birthday: "誕生日" | ||||
|   save: "保存" | ||||
|   locked-account: "アカウント守る" | ||||
|   is-locked: "他人のフォローは許してからや!" | ||||
|   is-locked: "他人のフォローは許可してからや!" | ||||
|   other: "その他" | ||||
|   is-bot: "このアカウントはBotやで" | ||||
|   is-cat: "このアカウントはCatやで" | ||||
| @@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue: | ||||
|   following: "フォローしとる" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォローの許し待っとる" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー許してくれや!言うてみる" | ||||
| mobile/views/components/friends-maker.vue: | ||||
|   title: "おもろそうやな" | ||||
| @@ -1185,97 +1222,98 @@ mobile/views/pages/settings/settings.profile.vue: | ||||
|   is-cat: "このアカウントはCatや" | ||||
|   is-locked: "他人のフォローは許してからや!" | ||||
|   advanced: "その他" | ||||
|   privacy: "プライバシー" | ||||
|   privacy: "プライバシー⇔オカンの年齢" | ||||
|   save: "保存" | ||||
|   saved: "プロフィールを保存しました" | ||||
|   uploading: "アップロード中" | ||||
|   upload-failed: "アップロードに失敗しました" | ||||
|   saved: "プロフィールを保存したで" | ||||
|   uploading: "アップロードしとるで…" | ||||
|   upload-failed: "これアップロードでけへんわ" | ||||
| mobile/views/pages/search.vue: | ||||
|   search: "検索" | ||||
|   empty: "「{}」に関する投稿は見つかりませんでした。" | ||||
|   not-found: "「{}」に関する投稿は見つかりませんでした。" | ||||
|   search: "探す" | ||||
|   empty: "ワイは「{}」なんて投稿知らんわ、無いんちゃう?知らんけど。" | ||||
|   not-found: "ワイは「{}」なんて投稿知らんわ、無いんちゃう?知らんけど。" | ||||
| mobile/views/pages/selectdrive.vue: | ||||
|   select-file: "ファイルを選択" | ||||
|   select-file: "ファイル選んでや" | ||||
| mobile/views/pages/settings.vue: | ||||
|   signed-in-as: "{}としてサインイン中" | ||||
|   signed-in-as: "あんたは橋の下で拾った{}や!" | ||||
|   lang: "言語" | ||||
|   lang-tip: "変更はページの再読み込み後に反映されます。" | ||||
|   recommended: "推奨" | ||||
|   auto: "自動" | ||||
|   specify-language: "言語を指定" | ||||
|   design: "デザインと表示" | ||||
|   dark-mode: "ダークモード" | ||||
|   i-am-under-limited-internet: "私は通信を制限されている" | ||||
|   circle-icons: "円形のアイコンを使用" | ||||
|   contrasted-acct: "ユーザー名にコントラストを付ける" | ||||
|   lang-tip: "ページもっぺん読み込んだら反映したるで。" | ||||
|   recommended: "これええで" | ||||
|   auto: "勝手にやる" | ||||
|   specify-language: "言語選びや" | ||||
|   design: "見た感じ" | ||||
|   dark-mode: "ナイトゲームや!" | ||||
|   i-am-under-limited-internet: "電波がバァーっといけへんねん" | ||||
|   circle-icons: "アイコンもタコ焼きも丸いやんな?" | ||||
|   contrasted-acct: "ユーザー名ようわからんし見やすしといて" | ||||
|   timeline: "タイムライン" | ||||
|   show-reply-target: "リプライ先を表示する" | ||||
|   show-my-renotes: "自分の行ったRenoteを表示する" | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteを表示する" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteを表示する" | ||||
|   show-reply-target: "どこにリプライするんや見せて" | ||||
|   show-my-renotes: "あんたのしたRenoteも出すで" | ||||
|   show-renoted-my-notes: "あんたの言うたことのRenoteも出すで" | ||||
|   show-local-renotes: "ローカル投稿のRenoteも出すで" | ||||
|   post-style: "投稿の表示スタイル" | ||||
|   post-style-standard: "標準" | ||||
|   post-style-smart: "べっぴんさん" | ||||
|   notification-position: "通知の表示" | ||||
|   notification-position-bottom: "下" | ||||
|   notification-position-top: "上" | ||||
|   behavior: "動作" | ||||
|   fetch-on-scroll: "スクロールで自動読み込み" | ||||
|   notification-position: "通知どこ見せる?" | ||||
|   notification-position-bottom: "ミナミ" | ||||
|   notification-position-top: "キタ" | ||||
|   theme: "テーマ" | ||||
|   behavior: "動き" | ||||
|   fetch-on-scroll: "スクロールしたらもっと見せてや" | ||||
|   note-visibility: "投稿の公開範囲" | ||||
|   default-note-visibility: "デフォルトの公開範囲" | ||||
|   remember-note-visibility: "投稿の公開範囲を記憶する" | ||||
|   disable-via-mobile: "「モバイルからの投稿」フラグを付けない" | ||||
|   load-raw-images: "添付された画像を高画質で表示する" | ||||
|   load-remote-media: "リモートサーバーのメディアを表示する" | ||||
|   twitter: "Twitter連携" | ||||
|   twitter-connect: "Twitterアカウントに接続する" | ||||
|   twitter-reconnect: "再接続する" | ||||
|   twitter-disconnect: "切断する" | ||||
|   update: "Misskey Update" | ||||
|   default-note-visibility: "もとからの公開範囲" | ||||
|   remember-note-visibility: "投稿の公開範囲おぼえといて" | ||||
|   disable-via-mobile: "「モバイルからの投稿」フラグなんて要らんわ" | ||||
|   load-raw-images: "添付された画像もべっぴんさんのままにしといてな" | ||||
|   load-remote-media: "東京とか、リモートサーバーのメディアも見せてや" | ||||
|   twitter: "鳥さんとも連携や!" | ||||
|   twitter-connect: "鳥さん邪魔すんで" | ||||
|   twitter-reconnect: "もっぺん繋ぎ直すで" | ||||
|   twitter-disconnect: "邪魔するんやったら帰って" | ||||
|   update: "あんたのMisskeyいつのや?" | ||||
|   version: "バージョン:" | ||||
|   latest-version: "最新のバージョン:" | ||||
|   update-checking: "アップデートを確認中" | ||||
|   check-for-updates: "アップデートを確認" | ||||
|   no-updates: "利用可能な更新はありません" | ||||
|   no-updates-desc: "お使いのMisskeyは最新です。" | ||||
|   update-available: "新しいバージョンが利用可能です" | ||||
|   update-available-desc: "ページを再度読み込みすると更新が適用されます。" | ||||
|   latest-version: "いっちゃん新しいやつ:" | ||||
|   update-checking: "アップデートはあらへんか…" | ||||
|   check-for-updates: "アップデートあるんかな?" | ||||
|   no-updates: "アップデートあらへんわ" | ||||
|   no-updates-desc: "つこてるMisskeyは最新や!" | ||||
|   update-available: "もっとええバージョンがあるで" | ||||
|   update-available-desc: "もっぺんページ読み込んだら新しなるで" | ||||
|   settings: "設定" | ||||
|   signout: "サインアウト" | ||||
|   signout: "さいなら" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   enable-sounds: "サウンド鳴らす" | ||||
| mobile/views/pages/user.vue: | ||||
|   follows-you: "フォローされています" | ||||
|   follows-you: "フォローされとるで" | ||||
|   following: "フォロー" | ||||
|   followers: "フォロワー" | ||||
|   notes: "投稿" | ||||
|   overview: "概要" | ||||
|   overview: "こんなやつ" | ||||
|   timeline: "タイムライン" | ||||
|   media: "メディア" | ||||
|   is-suspended: "このユーザーは凍結されています。" | ||||
|   is-remote: "このユーザーはリモートユーザーです。" | ||||
|   view-remote: "正確な情報を見る" | ||||
|   is-suspended: "このユーザーはあかんわ。凍結されとる。" | ||||
|   is-remote: "このユーザーは東京とかそこらへんのリモートユーザーや。" | ||||
|   view-remote: "ちゃんとした情報を見る" | ||||
| mobile/views/pages/user/home.vue: | ||||
|   recent-notes: "最近の投稿" | ||||
|   recent-notes: "最近儲かりまっか?" | ||||
|   images: "画像" | ||||
|   activity: "アクティビティ" | ||||
|   activity: "やっとること" | ||||
|   keywords: "キーワード" | ||||
|   domains: "頻出ドメイン" | ||||
|   frequently-replied-users: "よく会話するユーザー" | ||||
|   followers-you-know: "知り合いのフォロワー" | ||||
|   last-used-at: "最終ログイン" | ||||
|   domains: "よく出るドメイン" | ||||
|   frequently-replied-users: "よう話しとるユーザー" | ||||
|   followers-you-know: "知っとるフォロワー" | ||||
|   last-used-at: "最後いつ来た?" | ||||
| mobile/views/pages/user/home.followers-you-know.vue: | ||||
|   loading: "読み込み中" | ||||
|   no-users: "知り合いのユーザーはいません" | ||||
|   loading: "読み込んどる…" | ||||
|   no-users: "知っとるユーザーは居らん" | ||||
| mobile/views/pages/user/home.friends.vue: | ||||
|   loading: "読み込み中" | ||||
|   no-users: "よく会話するユーザーはいません" | ||||
|   loading: "読み込んどる…" | ||||
|   no-users: "よう話すユーザーは居らん" | ||||
| mobile/views/pages/user/home.notes.vue: | ||||
|   loading: "読み込み中" | ||||
|   no-notes: "投稿はありません" | ||||
|   loading: "読み込んどる…" | ||||
|   no-notes: "投稿はあらへん" | ||||
| mobile/views/pages/user/home.photos.vue: | ||||
|   loading: "読み込み中" | ||||
|   no-photos: "写真はありません" | ||||
|   loading: "読み込んどる…" | ||||
|   no-photos: "写真はあらへんで" | ||||
| docs: | ||||
|   edit-this-page-on-github: "間違いや改善点を見つけましたか?" | ||||
|   edit-this-page-on-github-link: "このページをGitHubで編集" | ||||
|   | ||||
| @@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue: | ||||
| common/views/components/media-banner.vue: | ||||
|   sensitive: "閲覧注意" | ||||
|   click-to-show: "クリックして表示" | ||||
| common/views/components/theme.vue: | ||||
|   light-theme: "非ダークモード時に使用するテーマ" | ||||
|   dark-theme: "ダークモード時に使用するテーマ" | ||||
|   light-themes: "明るいテーマ" | ||||
|   dark-themes: "暗いテーマ" | ||||
|   install-a-theme: "テーマのインストール" | ||||
|   theme-code: "テーマコード" | ||||
|   install: "インストール" | ||||
|   installed: "「{}」をインストールしました" | ||||
|   create-a-theme: "テーマの作成" | ||||
|   save-created-theme: "テーマを保存" | ||||
|   primary-color: "プライマリ カラー" | ||||
|   secondary-color: "セカンダリ カラー" | ||||
|   text-color: "文字色" | ||||
|   base-theme: "ベーステーマ" | ||||
|   base-theme-light: "Light" | ||||
|   base-theme-dark: "Dark" | ||||
|   theme-name: "テーマ名" | ||||
|   preview-created-theme: "プレビュー" | ||||
|   invalid-theme: "テーマが正しくありません。" | ||||
|   already-installed: "既にそのテーマはインストールされています。" | ||||
|   saved: "保存しました" | ||||
|   installed-themes: "インストールされたテーマ" | ||||
|   select-theme: "テーマを選択してください" | ||||
|   uninstall: "アンインストール" | ||||
|   uninstalled: "「{}」をアンインストールしました" | ||||
|   author: "作者" | ||||
|   desc: "説明" | ||||
|   export: "エクスポート" | ||||
|   import: "インポート" | ||||
|   import-by-code: "またはコードをペースト" | ||||
|   theme-name-required: "テーマ名は必須です。" | ||||
| common/views/components/cw-button.vue: | ||||
|   hide: "隠す" | ||||
|   show: "もっと見る" | ||||
| @@ -301,6 +333,7 @@ common/views/components/note-menu.vue: | ||||
|   copy-link: "リンクをコピー" | ||||
|   favorite: "お気に入り" | ||||
|   pin: "ピン留め" | ||||
|   unpin: "ピン留め解除" | ||||
|   delete: "削除" | ||||
|   delete-confirm: "この投稿を削除しますか?" | ||||
|   remote: "投稿元で見る" | ||||
| @@ -439,6 +472,7 @@ common/views/pages/follow.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| desktop: | ||||
|   banner-crop-title: "バナーとして表示する部分を選択" | ||||
| @@ -477,13 +511,13 @@ desktop/views/components/charts.vue: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     notes-total: "投稿の積算" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     users-total: "ユーザーの積算" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-total: "ドライブ使用量の積算" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
|     drive-files-total: "ドライブのファイル数の積算" | ||||
|     network-requests: "リクエスト" | ||||
|     network-time: "応答時間" | ||||
|     network-usage: "通信量" | ||||
| @@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| desktop/views/components/followers-window.vue: | ||||
|   followers: "{} のフォロワー" | ||||
| @@ -675,6 +710,7 @@ desktop/views/components/settings.vue: | ||||
|   2fa: "二段階認証" | ||||
|   other: "その他" | ||||
|   license: "ライセンス" | ||||
|   theme: "テーマ" | ||||
|   behaviour: "動作" | ||||
|   fetch-on-scroll: "スクロールで自動読み込み" | ||||
|   fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。" | ||||
| @@ -691,9 +727,10 @@ desktop/views/components/settings.vue: | ||||
|   choose-wallpaper: "壁紙を選択" | ||||
|   delete-wallpaper: "壁紙を削除" | ||||
|   dark-mode: "ダークモード" | ||||
|   use-shadow: "UIに影を使用" | ||||
|   rounded-corners: "UIの角を丸める" | ||||
|   circle-icons: "円形のアイコンを使用" | ||||
|   contrasted-acct: "ユーザー名にコントラストを付ける" | ||||
|   gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用" | ||||
|   post-form-on-timeline: "タイムライン上部に投稿フォームを表示する" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
| @@ -702,7 +739,6 @@ desktop/views/components/settings.vue: | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "マップの自動展開" | ||||
|   show-maps-desc: "位置情報が添付された投稿のマップを自動的に展開します。" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。" | ||||
| @@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| mobile/views/components/friends-maker.vue: | ||||
|   title: "気になるユーザーをフォロー" | ||||
| @@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue: | ||||
|   notification-position: "通知の表示" | ||||
|   notification-position-bottom: "下" | ||||
|   notification-position-top: "上" | ||||
|   theme: "テーマ" | ||||
|   behavior: "動作" | ||||
|   fetch-on-scroll: "スクロールで自動読み込み" | ||||
|   note-visibility: "投稿の公開範囲" | ||||
|   | ||||
| @@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue: | ||||
| common/views/components/media-banner.vue: | ||||
|   sensitive: "閲覧注意" | ||||
|   click-to-show: "クリックして表示" | ||||
| common/views/components/theme.vue: | ||||
|   light-theme: "非ダークモード時に使用するテーマ" | ||||
|   dark-theme: "ダークモード時に使用するテーマ" | ||||
|   light-themes: "明るいテーマ" | ||||
|   dark-themes: "暗いテーマ" | ||||
|   install-a-theme: "テーマのインストール" | ||||
|   theme-code: "テーマコード" | ||||
|   install: "インストール" | ||||
|   installed: "「{}」をインストールしました" | ||||
|   create-a-theme: "テーマの作成" | ||||
|   save-created-theme: "テーマを保存" | ||||
|   primary-color: "プライマリ カラー" | ||||
|   secondary-color: "セカンダリ カラー" | ||||
|   text-color: "文字色" | ||||
|   base-theme: "ベーステーマ" | ||||
|   base-theme-light: "Light" | ||||
|   base-theme-dark: "Dark" | ||||
|   theme-name: "テーマ名" | ||||
|   preview-created-theme: "プレビュー" | ||||
|   invalid-theme: "テーマが正しくありません。" | ||||
|   already-installed: "既にそのテーマはインストールされています。" | ||||
|   saved: "保存しました" | ||||
|   installed-themes: "インストールされたテーマ" | ||||
|   select-theme: "テーマを選択してください" | ||||
|   uninstall: "アンインストール" | ||||
|   uninstalled: "「{}」をアンインストールしました" | ||||
|   author: "作者" | ||||
|   desc: "説明" | ||||
|   export: "エクスポート" | ||||
|   import: "インポート" | ||||
|   import-by-code: "またはコードをペースト" | ||||
|   theme-name-required: "テーマ名は必須です。" | ||||
| common/views/components/cw-button.vue: | ||||
|   hide: "隠す" | ||||
|   show: "もっと見る" | ||||
| @@ -301,6 +333,7 @@ common/views/components/note-menu.vue: | ||||
|   copy-link: "リンクをコピー" | ||||
|   favorite: "Deze notitie toevoegen aan favorieten" | ||||
|   pin: "Vastmaken aan profielpagina" | ||||
|   unpin: "ピン留め解除" | ||||
|   delete: "削除" | ||||
|   delete-confirm: "この投稿を削除しますか?" | ||||
|   remote: "Origineel tonen" | ||||
| @@ -439,6 +472,7 @@ common/views/pages/follow.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| desktop: | ||||
|   banner-crop-title: "バナーとして表示する部分を選択" | ||||
| @@ -477,13 +511,13 @@ desktop/views/components/charts.vue: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     notes-total: "投稿の積算" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     users-total: "ユーザーの積算" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-total: "ドライブ使用量の積算" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
|     drive-files-total: "ドライブのファイル数の積算" | ||||
|     network-requests: "リクエスト" | ||||
|     network-time: "応答時間" | ||||
|     network-usage: "通信量" | ||||
| @@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "Volgen" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| desktop/views/components/followers-window.vue: | ||||
|   followers: "Volgers van {}" | ||||
| @@ -675,6 +710,7 @@ desktop/views/components/settings.vue: | ||||
|   2fa: "Authenticatie in twee stappen" | ||||
|   other: "Overig" | ||||
|   license: "Licentie" | ||||
|   theme: "テーマ" | ||||
|   behaviour: "Gedrag" | ||||
|   fetch-on-scroll: "Ophalen bij scrollen" | ||||
|   fetch-on-scroll-desc: "Als je omlaag scrolt, wordt de rest van de inhoud automatisch opgehaald." | ||||
| @@ -691,9 +727,10 @@ desktop/views/components/settings.vue: | ||||
|   choose-wallpaper: "壁紙を選択" | ||||
|   delete-wallpaper: "壁紙を削除" | ||||
|   dark-mode: "Donkere modus" | ||||
|   use-shadow: "UIに影を使用" | ||||
|   rounded-corners: "UIの角を丸める" | ||||
|   circle-icons: "Ronde pictogrammen gebruiken" | ||||
|   contrasted-acct: "ユーザー名にコントラストを付ける" | ||||
|   gradient-window-header: "Kleurverloop gebruiken op vensterkoppen" | ||||
|   post-form-on-timeline: "Berichtformulier boven de tijdlijn tonen" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
| @@ -702,7 +739,6 @@ desktop/views/components/settings.vue: | ||||
|   show-renoted-my-notes: "Mijn gerenote bericht tonen op de tijdlijn" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "Kaart tonen" | ||||
|   show-maps-desc: "Kaart van bijgevoegde locatie tonen." | ||||
|   sound: "Geluid" | ||||
|   enable-sounds: "Geluid inschakelen" | ||||
|   enable-sounds-desc: "Een geluid afspelen bij het ontvangen van een bericht. Deze instelling wordt opgeslagen in je browser." | ||||
| @@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "Volgen" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| mobile/views/components/friends-maker.vue: | ||||
|   title: "気になるユーザーをフォロー" | ||||
| @@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue: | ||||
|   notification-position: "通知の表示" | ||||
|   notification-position-bottom: "下" | ||||
|   notification-position-top: "上" | ||||
|   theme: "テーマ" | ||||
|   behavior: "Gedrag" | ||||
|   fetch-on-scroll: "Ophalen bij scrollen" | ||||
|   note-visibility: "投稿の公開範囲" | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue: | ||||
| common/views/components/media-banner.vue: | ||||
|   sensitive: "閲覧注意" | ||||
|   click-to-show: "クリックして表示" | ||||
| common/views/components/theme.vue: | ||||
|   light-theme: "非ダークモード時に使用するテーマ" | ||||
|   dark-theme: "ダークモード時に使用するテーマ" | ||||
|   light-themes: "明るいテーマ" | ||||
|   dark-themes: "暗いテーマ" | ||||
|   install-a-theme: "テーマのインストール" | ||||
|   theme-code: "テーマコード" | ||||
|   install: "インストール" | ||||
|   installed: "「{}」をインストールしました" | ||||
|   create-a-theme: "テーマの作成" | ||||
|   save-created-theme: "テーマを保存" | ||||
|   primary-color: "プライマリ カラー" | ||||
|   secondary-color: "セカンダリ カラー" | ||||
|   text-color: "文字色" | ||||
|   base-theme: "ベーステーマ" | ||||
|   base-theme-light: "Light" | ||||
|   base-theme-dark: "Dark" | ||||
|   theme-name: "テーマ名" | ||||
|   preview-created-theme: "プレビュー" | ||||
|   invalid-theme: "テーマが正しくありません。" | ||||
|   already-installed: "既にそのテーマはインストールされています。" | ||||
|   saved: "保存しました" | ||||
|   installed-themes: "インストールされたテーマ" | ||||
|   select-theme: "テーマを選択してください" | ||||
|   uninstall: "アンインストール" | ||||
|   uninstalled: "「{}」をアンインストールしました" | ||||
|   author: "作者" | ||||
|   desc: "説明" | ||||
|   export: "エクスポート" | ||||
|   import: "インポート" | ||||
|   import-by-code: "またはコードをペースト" | ||||
|   theme-name-required: "テーマ名は必須です。" | ||||
| common/views/components/cw-button.vue: | ||||
|   hide: "隠す" | ||||
|   show: "もっと見る" | ||||
| @@ -301,6 +333,7 @@ common/views/components/note-menu.vue: | ||||
|   copy-link: "リンクをコピー" | ||||
|   favorite: "Dodaj do ulubionych" | ||||
|   pin: "Przypnij do profilu" | ||||
|   unpin: "ピン留め解除" | ||||
|   delete: "Usuń" | ||||
|   delete-confirm: "Czy na pewno chcesz usunąć ten wpis?" | ||||
|   remote: "Pokaż oryginał" | ||||
| @@ -439,6 +472,7 @@ common/views/pages/follow.vue: | ||||
|   following: "Śledzisz" | ||||
|   follow: "Śledź" | ||||
|   request-pending: "Oczekiwanie na pozwolenie" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "Poproś o śledzenie" | ||||
| desktop: | ||||
|   banner-crop-title: "バナーとして表示する部分を選択" | ||||
| @@ -477,13 +511,13 @@ desktop/views/components/charts.vue: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     notes-total: "投稿の積算" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     users-total: "ユーザーの積算" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-total: "ドライブ使用量の積算" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
|     drive-files-total: "ドライブのファイル数の積算" | ||||
|     network-requests: "リクエスト" | ||||
|     network-time: "応答時間" | ||||
|     network-usage: "通信量" | ||||
| @@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue: | ||||
|   following: "Śledzisz" | ||||
|   follow: "Śledź" | ||||
|   request-pending: "Oczekiwanie na pozwolenie" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "Poproś o śledzenie" | ||||
| desktop/views/components/followers-window.vue: | ||||
|   followers: "Śledzący" | ||||
| @@ -675,6 +710,7 @@ desktop/views/components/settings.vue: | ||||
|   2fa: "Uwierzytelnianie dwuetapowe" | ||||
|   other: "Inne" | ||||
|   license: "Licencja" | ||||
|   theme: "テーマ" | ||||
|   behaviour: "Zachowanie" | ||||
|   fetch-on-scroll: "Automatycznie ładuj po przeciągnięciu w dół" | ||||
|   fetch-on-scroll-desc: "Po przewinięciu na dół strony automatycznie zostaną załadowane nowe treści." | ||||
| @@ -691,9 +727,10 @@ desktop/views/components/settings.vue: | ||||
|   choose-wallpaper: "Wybierz tło" | ||||
|   delete-wallpaper: "Usuń tło" | ||||
|   dark-mode: "Tryb ciemny" | ||||
|   use-shadow: "UIに影を使用" | ||||
|   rounded-corners: "UIの角を丸める" | ||||
|   circle-icons: "Używaj okrągłych ikon" | ||||
|   contrasted-acct: "ユーザー名にコントラストを付ける" | ||||
|   gradient-window-header: "Używaj gradientów na pasku tytułu okna" | ||||
|   post-form-on-timeline: "Wyświetlaj formularz tworzenia wpisu w górnej części osi czasu" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
| @@ -702,7 +739,6 @@ desktop/views/components/settings.vue: | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "Automatycznie pokazuj mapę" | ||||
|   show-maps-desc: "Mapa będzie automatycznie rozwijana dla wpisów zawierających informacje o lokalizacji." | ||||
|   sound: "Dźwięk" | ||||
|   enable-sounds: "Włącz dźwięk" | ||||
|   enable-sounds-desc: "Odtwarzaj dźwięk przy wstawianiu wpisów, wysyłaniu lub otrzymywaniu wiadomości. Opcja ta jest zapamiętywana przez przeglądarkę." | ||||
| @@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue: | ||||
|   following: "Śledzisz" | ||||
|   follow: "Śledź" | ||||
|   request-pending: "Oczekiwanie na pozwolenie" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "Poproś o śledzenie" | ||||
| mobile/views/components/friends-maker.vue: | ||||
|   title: "Zacznij śledzić ludzi takich jak Ty" | ||||
| @@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue: | ||||
|   notification-position: "通知の表示" | ||||
|   notification-position-bottom: "下" | ||||
|   notification-position-top: "上" | ||||
|   theme: "テーマ" | ||||
|   behavior: "Zachowanie" | ||||
|   fetch-on-scroll: "Automatycznie ładuj po przeciągnięciu w dół" | ||||
|   note-visibility: "投稿の公開範囲" | ||||
|   | ||||
| @@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue: | ||||
| common/views/components/media-banner.vue: | ||||
|   sensitive: "閲覧注意" | ||||
|   click-to-show: "クリックして表示" | ||||
| common/views/components/theme.vue: | ||||
|   light-theme: "非ダークモード時に使用するテーマ" | ||||
|   dark-theme: "ダークモード時に使用するテーマ" | ||||
|   light-themes: "明るいテーマ" | ||||
|   dark-themes: "暗いテーマ" | ||||
|   install-a-theme: "テーマのインストール" | ||||
|   theme-code: "テーマコード" | ||||
|   install: "インストール" | ||||
|   installed: "「{}」をインストールしました" | ||||
|   create-a-theme: "テーマの作成" | ||||
|   save-created-theme: "テーマを保存" | ||||
|   primary-color: "プライマリ カラー" | ||||
|   secondary-color: "セカンダリ カラー" | ||||
|   text-color: "文字色" | ||||
|   base-theme: "ベーステーマ" | ||||
|   base-theme-light: "Light" | ||||
|   base-theme-dark: "Dark" | ||||
|   theme-name: "テーマ名" | ||||
|   preview-created-theme: "プレビュー" | ||||
|   invalid-theme: "テーマが正しくありません。" | ||||
|   already-installed: "既にそのテーマはインストールされています。" | ||||
|   saved: "保存しました" | ||||
|   installed-themes: "インストールされたテーマ" | ||||
|   select-theme: "テーマを選択してください" | ||||
|   uninstall: "アンインストール" | ||||
|   uninstalled: "「{}」をアンインストールしました" | ||||
|   author: "作者" | ||||
|   desc: "説明" | ||||
|   export: "エクスポート" | ||||
|   import: "インポート" | ||||
|   import-by-code: "またはコードをペースト" | ||||
|   theme-name-required: "テーマ名は必須です。" | ||||
| common/views/components/cw-button.vue: | ||||
|   hide: "隠す" | ||||
|   show: "もっと見る" | ||||
| @@ -301,6 +333,7 @@ common/views/components/note-menu.vue: | ||||
|   copy-link: "リンクをコピー" | ||||
|   favorite: "お気に入り" | ||||
|   pin: "ピン留め" | ||||
|   unpin: "ピン留め解除" | ||||
|   delete: "削除" | ||||
|   delete-confirm: "この投稿を削除しますか?" | ||||
|   remote: "投稿元で見る" | ||||
| @@ -439,6 +472,7 @@ common/views/pages/follow.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| desktop: | ||||
|   banner-crop-title: "バナーとして表示する部分を選択" | ||||
| @@ -477,13 +511,13 @@ desktop/views/components/charts.vue: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     notes-total: "投稿の積算" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     users-total: "ユーザーの積算" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-total: "ドライブ使用量の積算" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
|     drive-files-total: "ドライブのファイル数の積算" | ||||
|     network-requests: "リクエスト" | ||||
|     network-time: "応答時間" | ||||
|     network-usage: "通信量" | ||||
| @@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| desktop/views/components/followers-window.vue: | ||||
|   followers: "{} のフォロワー" | ||||
| @@ -675,6 +710,7 @@ desktop/views/components/settings.vue: | ||||
|   2fa: "二段階認証" | ||||
|   other: "その他" | ||||
|   license: "ライセンス" | ||||
|   theme: "テーマ" | ||||
|   behaviour: "動作" | ||||
|   fetch-on-scroll: "スクロールで自動読み込み" | ||||
|   fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。" | ||||
| @@ -691,9 +727,10 @@ desktop/views/components/settings.vue: | ||||
|   choose-wallpaper: "壁紙を選択" | ||||
|   delete-wallpaper: "壁紙を削除" | ||||
|   dark-mode: "ダークモード" | ||||
|   use-shadow: "UIに影を使用" | ||||
|   rounded-corners: "UIの角を丸める" | ||||
|   circle-icons: "円形のアイコンを使用" | ||||
|   contrasted-acct: "ユーザー名にコントラストを付ける" | ||||
|   gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用" | ||||
|   post-form-on-timeline: "タイムライン上部に投稿フォームを表示する" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
| @@ -702,7 +739,6 @@ desktop/views/components/settings.vue: | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "マップの自動展開" | ||||
|   show-maps-desc: "位置情報が添付された投稿のマップを自動的に展開します。" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。" | ||||
| @@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| mobile/views/components/friends-maker.vue: | ||||
|   title: "気になるユーザーをフォロー" | ||||
| @@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue: | ||||
|   notification-position: "通知の表示" | ||||
|   notification-position-bottom: "下" | ||||
|   notification-position-top: "上" | ||||
|   theme: "テーマ" | ||||
|   behavior: "動作" | ||||
|   fetch-on-scroll: "スクロールで自動読み込み" | ||||
|   note-visibility: "投稿の公開範囲" | ||||
|   | ||||
| @@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue: | ||||
| common/views/components/media-banner.vue: | ||||
|   sensitive: "閲覧注意" | ||||
|   click-to-show: "クリックして表示" | ||||
| common/views/components/theme.vue: | ||||
|   light-theme: "非ダークモード時に使用するテーマ" | ||||
|   dark-theme: "ダークモード時に使用するテーマ" | ||||
|   light-themes: "明るいテーマ" | ||||
|   dark-themes: "暗いテーマ" | ||||
|   install-a-theme: "テーマのインストール" | ||||
|   theme-code: "テーマコード" | ||||
|   install: "インストール" | ||||
|   installed: "「{}」をインストールしました" | ||||
|   create-a-theme: "テーマの作成" | ||||
|   save-created-theme: "テーマを保存" | ||||
|   primary-color: "プライマリ カラー" | ||||
|   secondary-color: "セカンダリ カラー" | ||||
|   text-color: "文字色" | ||||
|   base-theme: "ベーステーマ" | ||||
|   base-theme-light: "Light" | ||||
|   base-theme-dark: "Dark" | ||||
|   theme-name: "テーマ名" | ||||
|   preview-created-theme: "プレビュー" | ||||
|   invalid-theme: "テーマが正しくありません。" | ||||
|   already-installed: "既にそのテーマはインストールされています。" | ||||
|   saved: "保存しました" | ||||
|   installed-themes: "インストールされたテーマ" | ||||
|   select-theme: "テーマを選択してください" | ||||
|   uninstall: "アンインストール" | ||||
|   uninstalled: "「{}」をアンインストールしました" | ||||
|   author: "作者" | ||||
|   desc: "説明" | ||||
|   export: "エクスポート" | ||||
|   import: "インポート" | ||||
|   import-by-code: "またはコードをペースト" | ||||
|   theme-name-required: "テーマ名は必須です。" | ||||
| common/views/components/cw-button.vue: | ||||
|   hide: "隠す" | ||||
|   show: "もっと見る" | ||||
| @@ -301,6 +333,7 @@ common/views/components/note-menu.vue: | ||||
|   copy-link: "リンクをコピー" | ||||
|   favorite: "お気に入り" | ||||
|   pin: "ピン留め" | ||||
|   unpin: "ピン留め解除" | ||||
|   delete: "削除" | ||||
|   delete-confirm: "この投稿を削除しますか?" | ||||
|   remote: "投稿元で見る" | ||||
| @@ -439,6 +472,7 @@ common/views/pages/follow.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| desktop: | ||||
|   banner-crop-title: "バナーとして表示する部分を選択" | ||||
| @@ -477,13 +511,13 @@ desktop/views/components/charts.vue: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     notes-total: "投稿の積算" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     users-total: "ユーザーの積算" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-total: "ドライブ使用量の積算" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
|     drive-files-total: "ドライブのファイル数の積算" | ||||
|     network-requests: "リクエスト" | ||||
|     network-time: "応答時間" | ||||
|     network-usage: "通信量" | ||||
| @@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| desktop/views/components/followers-window.vue: | ||||
|   followers: "{} のフォロワー" | ||||
| @@ -675,6 +710,7 @@ desktop/views/components/settings.vue: | ||||
|   2fa: "二段階認証" | ||||
|   other: "その他" | ||||
|   license: "ライセンス" | ||||
|   theme: "テーマ" | ||||
|   behaviour: "動作" | ||||
|   fetch-on-scroll: "スクロールで自動読み込み" | ||||
|   fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。" | ||||
| @@ -691,9 +727,10 @@ desktop/views/components/settings.vue: | ||||
|   choose-wallpaper: "壁紙を選択" | ||||
|   delete-wallpaper: "壁紙を削除" | ||||
|   dark-mode: "ダークモード" | ||||
|   use-shadow: "UIに影を使用" | ||||
|   rounded-corners: "UIの角を丸める" | ||||
|   circle-icons: "円形のアイコンを使用" | ||||
|   contrasted-acct: "ユーザー名にコントラストを付ける" | ||||
|   gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用" | ||||
|   post-form-on-timeline: "タイムライン上部に投稿フォームを表示する" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
| @@ -702,7 +739,6 @@ desktop/views/components/settings.vue: | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "マップの自動展開" | ||||
|   show-maps-desc: "位置情報が添付された投稿のマップを自動的に展開します。" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。" | ||||
| @@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| mobile/views/components/friends-maker.vue: | ||||
|   title: "気になるユーザーをフォロー" | ||||
| @@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue: | ||||
|   notification-position: "通知の表示" | ||||
|   notification-position-bottom: "下" | ||||
|   notification-position-top: "上" | ||||
|   theme: "テーマ" | ||||
|   behavior: "動作" | ||||
|   fetch-on-scroll: "スクロールで自動読み込み" | ||||
|   note-visibility: "投稿の公開範囲" | ||||
|   | ||||
| @@ -264,6 +264,38 @@ common/views/components/connect-failed.troubleshooter.vue: | ||||
| common/views/components/media-banner.vue: | ||||
|   sensitive: "閲覧注意" | ||||
|   click-to-show: "クリックして表示" | ||||
| common/views/components/theme.vue: | ||||
|   light-theme: "非ダークモード時に使用するテーマ" | ||||
|   dark-theme: "ダークモード時に使用するテーマ" | ||||
|   light-themes: "明るいテーマ" | ||||
|   dark-themes: "暗いテーマ" | ||||
|   install-a-theme: "テーマのインストール" | ||||
|   theme-code: "テーマコード" | ||||
|   install: "インストール" | ||||
|   installed: "「{}」をインストールしました" | ||||
|   create-a-theme: "テーマの作成" | ||||
|   save-created-theme: "テーマを保存" | ||||
|   primary-color: "プライマリ カラー" | ||||
|   secondary-color: "セカンダリ カラー" | ||||
|   text-color: "文字色" | ||||
|   base-theme: "ベーステーマ" | ||||
|   base-theme-light: "Light" | ||||
|   base-theme-dark: "Dark" | ||||
|   theme-name: "テーマ名" | ||||
|   preview-created-theme: "プレビュー" | ||||
|   invalid-theme: "テーマが正しくありません。" | ||||
|   already-installed: "既にそのテーマはインストールされています。" | ||||
|   saved: "保存しました" | ||||
|   installed-themes: "インストールされたテーマ" | ||||
|   select-theme: "テーマを選択してください" | ||||
|   uninstall: "アンインストール" | ||||
|   uninstalled: "「{}」をアンインストールしました" | ||||
|   author: "作者" | ||||
|   desc: "説明" | ||||
|   export: "エクスポート" | ||||
|   import: "インポート" | ||||
|   import-by-code: "またはコードをペースト" | ||||
|   theme-name-required: "テーマ名は必須です。" | ||||
| common/views/components/cw-button.vue: | ||||
|   hide: "隠す" | ||||
|   show: "もっと見る" | ||||
| @@ -301,6 +333,7 @@ common/views/components/note-menu.vue: | ||||
|   copy-link: "リンクをコピー" | ||||
|   favorite: "お気に入り" | ||||
|   pin: "ピン留め" | ||||
|   unpin: "ピン留め解除" | ||||
|   delete: "削除" | ||||
|   delete-confirm: "この投稿を削除しますか?" | ||||
|   remote: "投稿元で見る" | ||||
| @@ -439,6 +472,7 @@ common/views/pages/follow.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| desktop: | ||||
|   banner-crop-title: "バナーとして表示する部分を選択" | ||||
| @@ -477,13 +511,13 @@ desktop/views/components/charts.vue: | ||||
|     notes: "投稿の増減 (統合)" | ||||
|     local-notes: "投稿の増減 (ローカル)" | ||||
|     remote-notes: "投稿の増減 (リモート)" | ||||
|     notes-total: "投稿の累計" | ||||
|     notes-total: "投稿の積算" | ||||
|     users: "ユーザーの増減" | ||||
|     users-total: "ユーザーの累計" | ||||
|     users-total: "ユーザーの積算" | ||||
|     drive: "ドライブ使用量の増減" | ||||
|     drive-total: "ドライブ使用量の累計" | ||||
|     drive-total: "ドライブ使用量の積算" | ||||
|     drive-files: "ドライブのファイル数の増減" | ||||
|     drive-files-total: "ドライブのファイル数の累計" | ||||
|     drive-files-total: "ドライブのファイル数の積算" | ||||
|     network-requests: "リクエスト" | ||||
|     network-time: "応答時間" | ||||
|     network-usage: "通信量" | ||||
| @@ -565,6 +599,7 @@ desktop/views/components/follow-button.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| desktop/views/components/followers-window.vue: | ||||
|   followers: "{} のフォロワー" | ||||
| @@ -675,6 +710,7 @@ desktop/views/components/settings.vue: | ||||
|   2fa: "二段階認証" | ||||
|   other: "その他" | ||||
|   license: "ライセンス" | ||||
|   theme: "テーマ" | ||||
|   behaviour: "動作" | ||||
|   fetch-on-scroll: "スクロールで自動読み込み" | ||||
|   fetch-on-scroll-desc: "ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。" | ||||
| @@ -691,9 +727,10 @@ desktop/views/components/settings.vue: | ||||
|   choose-wallpaper: "壁紙を選択" | ||||
|   delete-wallpaper: "壁紙を削除" | ||||
|   dark-mode: "ダークモード" | ||||
|   use-shadow: "UIに影を使用" | ||||
|   rounded-corners: "UIの角を丸める" | ||||
|   circle-icons: "円形のアイコンを使用" | ||||
|   contrasted-acct: "ユーザー名にコントラストを付ける" | ||||
|   gradient-window-header: "ウィンドウのタイトルバーにグラデーションを使用" | ||||
|   post-form-on-timeline: "タイムライン上部に投稿フォームを表示する" | ||||
|   suggest-recent-hashtags: "最近のハッシュタグを投稿フォームに表示する" | ||||
|   show-clock-on-header: "右上に時計を表示する" | ||||
| @@ -702,7 +739,6 @@ desktop/views/components/settings.vue: | ||||
|   show-renoted-my-notes: "自分の投稿のRenoteをタイムラインに表示する" | ||||
|   show-local-renotes: "ローカルの投稿のRenoteをタイムラインに表示する" | ||||
|   show-maps: "マップの自動展開" | ||||
|   show-maps-desc: "位置情報が添付された投稿のマップを自動的に展開します。" | ||||
|   sound: "サウンド" | ||||
|   enable-sounds: "サウンドを有効にする" | ||||
|   enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。" | ||||
| @@ -1044,6 +1080,7 @@ mobile/views/components/follow-button.vue: | ||||
|   following: "フォロー中" | ||||
|   follow: "フォロー" | ||||
|   request-pending: "フォロー許可待ち" | ||||
|   follow-processing: "フォロー処理中" | ||||
|   follow-request: "フォロー申請" | ||||
| mobile/views/components/friends-maker.vue: | ||||
|   title: "気になるユーザーをフォロー" | ||||
| @@ -1219,6 +1256,7 @@ mobile/views/pages/settings.vue: | ||||
|   notification-position: "通知の表示" | ||||
|   notification-position-bottom: "下" | ||||
|   notification-position-top: "上" | ||||
|   theme: "テーマ" | ||||
|   behavior: "動作" | ||||
|   fetch-on-scroll: "スクロールで自動読み込み" | ||||
|   note-visibility: "投稿の公開範囲" | ||||
|   | ||||
							
								
								
									
										55
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										55
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,8 +1,8 @@ | ||||
| { | ||||
| 	"name": "misskey", | ||||
| 	"author": "syuilo <i@syuilo.com>", | ||||
| 	"version": "8.58.0", | ||||
| 	"clientVersion": "1.0.9945", | ||||
| 	"version": "10.2.0", | ||||
| 	"clientVersion": "1.0.10362", | ||||
| 	"codename": "nighthike", | ||||
| 	"main": "./built/index.js", | ||||
| 	"private": true, | ||||
| @@ -29,7 +29,7 @@ | ||||
| 		"@prezzemolo/zip": "0.0.3", | ||||
| 		"@types/bcryptjs": "2.4.2", | ||||
| 		"@types/dateformat": "1.0.1", | ||||
| 		"@types/debug": "0.0.30", | ||||
| 		"@types/debug": "0.0.31", | ||||
| 		"@types/deep-equal": "1.0.1", | ||||
| 		"@types/double-ended-queue": "2.1.0", | ||||
| 		"@types/elasticsearch": "5.0.26", | ||||
| @@ -58,12 +58,12 @@ | ||||
| 		"@types/minio": "7.0.0", | ||||
| 		"@types/mkdirp": "0.5.2", | ||||
| 		"@types/mocha": "5.2.3", | ||||
| 		"@types/mongodb": "3.1.7", | ||||
| 		"@types/mongodb": "3.1.10", | ||||
| 		"@types/ms": "0.7.30", | ||||
| 		"@types/node": "10.10.3", | ||||
| 		"@types/node": "10.11.4", | ||||
| 		"@types/portscanner": "2.1.0", | ||||
| 		"@types/pug": "2.0.4", | ||||
| 		"@types/qrcode": "1.2.0", | ||||
| 		"@types/qrcode": "1.3.0", | ||||
| 		"@types/ratelimiter": "2.1.28", | ||||
| 		"@types/redis": "2.8.6", | ||||
| 		"@types/request": "2.47.1", | ||||
| @@ -75,13 +75,15 @@ | ||||
| 		"@types/single-line-log": "1.1.0", | ||||
| 		"@types/speakeasy": "2.0.2", | ||||
| 		"@types/systeminformation": "3.23.0", | ||||
| 		"@types/tinycolor2": "1.4.1", | ||||
| 		"@types/tmp": "0.0.33", | ||||
| 		"@types/uuid": "3.4.4", | ||||
| 		"@types/webpack": "4.4.12", | ||||
| 		"@types/webpack": "4.4.14", | ||||
| 		"@types/webpack-stream": "3.2.10", | ||||
| 		"@types/websocket": "0.0.40", | ||||
| 		"@types/ws": "6.0.1", | ||||
| 		"animejs": "2.2.0", | ||||
| 		"autobind-decorator": "2.1.0", | ||||
| 		"autosize": "4.0.2", | ||||
| 		"autwh": "0.1.0", | ||||
| 		"bcryptjs": "2.4.3", | ||||
| @@ -94,10 +96,10 @@ | ||||
| 		"crc-32": "1.2.0", | ||||
| 		"css-loader": "1.0.0", | ||||
| 		"dateformat": "3.0.3", | ||||
| 		"debug": "4.0.1", | ||||
| 		"debug": "4.1.0", | ||||
| 		"deep-equal": "1.0.1", | ||||
| 		"deepcopy": "0.6.3", | ||||
| 		"diskusage": "0.2.4", | ||||
| 		"diskusage": "0.2.5", | ||||
| 		"dompurify": "1.0.5", | ||||
| 		"double-ended-queue": "2.1.0-0", | ||||
| 		"elasticsearch": "15.1.1", | ||||
| @@ -107,12 +109,12 @@ | ||||
| 		"eslint-plugin-vue": "4.7.1", | ||||
| 		"eventemitter3": "3.1.0", | ||||
| 		"exif-js": "2.3.0", | ||||
| 		"file-loader": "1.1.11", | ||||
| 		"file-type": "9.0.0", | ||||
| 		"file-loader": "2.0.0", | ||||
| 		"file-type": "10.0.0", | ||||
| 		"fuckadblock": "3.2.1", | ||||
| 		"gulp": "3.9.1", | ||||
| 		"gulp-cssnano": "2.1.3", | ||||
| 		"gulp-htmlmin": "4.0.0", | ||||
| 		"gulp-htmlmin": "5.0.1", | ||||
| 		"gulp-imagemin": "4.1.0", | ||||
| 		"gulp-mocha": "6.0.0", | ||||
| 		"gulp-pug": "4.0.1", | ||||
| @@ -132,14 +134,16 @@ | ||||
| 		"is-root": "2.0.0", | ||||
| 		"is-url": "1.2.4", | ||||
| 		"js-yaml": "3.12.0", | ||||
| 		"jsdom": "11.12.0", | ||||
| 		"jsdom": "12.2.0", | ||||
| 		"json5": "2.1.0", | ||||
| 		"json5-loader": "1.0.1", | ||||
| 		"koa": "2.5.1", | ||||
| 		"koa-bodyparser": "4.2.1", | ||||
| 		"koa-compress": "3.0.0", | ||||
| 		"koa-favicon": "2.0.1", | ||||
| 		"koa-json-body": "5.3.0", | ||||
| 		"koa-logger": "3.2.0", | ||||
| 		"koa-mount": "3.0.0", | ||||
| 		"koa-mount": "4.0.0", | ||||
| 		"koa-multer": "1.0.2", | ||||
| 		"koa-router": "7.4.0", | ||||
| 		"koa-send": "5.0.0", | ||||
| @@ -156,7 +160,7 @@ | ||||
| 		"mongodb": "3.1.1", | ||||
| 		"monk": "6.0.6", | ||||
| 		"ms": "2.1.1", | ||||
| 		"nan": "2.11.0", | ||||
| 		"nan": "2.11.1", | ||||
| 		"nested-property": "0.0.7", | ||||
| 		"nprogress": "0.2.0", | ||||
| 		"object-assign-deep": "0.4.0", | ||||
| @@ -168,10 +172,10 @@ | ||||
| 		"promise-sequential": "1.1.1", | ||||
| 		"pug": "2.0.3", | ||||
| 		"punycode": "2.1.1", | ||||
| 		"qrcode": "1.2.2", | ||||
| 		"qrcode": "1.3.0", | ||||
| 		"ratelimiter": "3.2.0", | ||||
| 		"recaptcha-promise": "0.1.3", | ||||
| 		"reconnecting-websocket": "3.2.2", | ||||
| 		"reconnecting-websocket": "4.1.5", | ||||
| 		"redis": "2.8.0", | ||||
| 		"request": "2.88.0", | ||||
| 		"request-promise-native": "1.0.5", | ||||
| @@ -181,37 +185,40 @@ | ||||
| 		"s-age": "1.1.2", | ||||
| 		"sass-loader": "7.1.0", | ||||
| 		"seedrandom": "2.4.4", | ||||
| 		"sharp": "0.20.7", | ||||
| 		"sharp": "0.21.0", | ||||
| 		"showdown": "1.8.6", | ||||
| 		"showdown-highlightjs-extension": "0.1.2", | ||||
| 		"single-line-log": "1.1.2", | ||||
| 		"speakeasy": "2.0.0", | ||||
| 		"stringz": "1.0.0", | ||||
| 		"style-loader": "0.23.0", | ||||
| 		"style-loader": "0.23.1", | ||||
| 		"stylus": "0.54.5", | ||||
| 		"stylus-loader": "3.0.2", | ||||
| 		"summaly": "2.2.0", | ||||
| 		"systeminformation": "3.45.6", | ||||
| 		"systeminformation": "3.45.7", | ||||
| 		"syuilo-password-strength": "0.0.1", | ||||
| 		"textarea-caret": "3.1.0", | ||||
| 		"tinycolor2": "1.4.1", | ||||
| 		"tmp": "0.0.33", | ||||
| 		"ts-loader": "4.4.1", | ||||
| 		"ts-node": "7.0.1", | ||||
| 		"tslint": "5.10.0", | ||||
| 		"typescript": "2.9.2", | ||||
| 		"typescript-eslint-parser": "18.0.0", | ||||
| 		"typescript-eslint-parser": "20.0.0", | ||||
| 		"uglify-es": "3.3.9", | ||||
| 		"url-loader": "1.1.1", | ||||
| 		"uuid": "3.3.2", | ||||
| 		"v-animate-css": "0.0.2", | ||||
| 		"vue": "2.5.17", | ||||
| 		"vue-chartjs": "3.4.0", | ||||
| 		"vue-color": "2.6.0", | ||||
| 		"vue-cropperjs": "2.2.2", | ||||
| 		"vue-js-modal": "1.3.26", | ||||
| 		"vue-json-tree-view": "2.1.4", | ||||
| 		"vue-loader": "15.4.2", | ||||
| 		"vue-router": "3.0.1", | ||||
| 		"vue-style-loader": "4.1.2", | ||||
| 		"vue-svg-inline-loader": "1.2.0", | ||||
| 		"vue-template-compiler": "2.5.17", | ||||
| 		"vuedraggable": "2.16.0", | ||||
| 		"vuewordcloud": "18.7.11", | ||||
| @@ -219,10 +226,10 @@ | ||||
| 		"vuex-persistedstate": "2.5.4", | ||||
| 		"web-push": "3.3.3", | ||||
| 		"webfinger.js": "2.6.6", | ||||
| 		"webpack": "4.19.1", | ||||
| 		"webpack-cli": "3.1.0", | ||||
| 		"webpack": "4.20.2", | ||||
| 		"webpack-cli": "3.1.2", | ||||
| 		"websocket": "1.0.28", | ||||
| 		"ws": "6.0.0", | ||||
| 		"ws": "6.1.0", | ||||
| 		"xev": "2.0.1" | ||||
| 	}, | ||||
| 	"greenkeeper": { | ||||
|   | ||||
| @@ -27,7 +27,7 @@ body | ||||
| 	z-index 65536 | ||||
|  | ||||
| 	.bar | ||||
| 		background $theme-color | ||||
| 		background var(--primary) | ||||
|  | ||||
| 		position fixed | ||||
| 		z-index 65537 | ||||
| @@ -44,7 +44,7 @@ body | ||||
| 		right 0px | ||||
| 		width 100px | ||||
| 		height 100% | ||||
| 		box-shadow 0 0 10px $theme-color, 0 0 5px $theme-color | ||||
| 		box-shadow 0 0 10px var(--primary), 0 0 5px var(--primary) | ||||
| 		opacity 1 | ||||
|  | ||||
| 		transform rotate(3deg) translate(0px, -4px) | ||||
| @@ -64,8 +64,8 @@ body | ||||
| 		box-sizing border-box | ||||
|  | ||||
| 		border solid 2px transparent | ||||
| 		border-top-color $theme-color | ||||
| 		border-left-color $theme-color | ||||
| 		border-top-color var(--primary) | ||||
| 		border-left-color var(--primary) | ||||
| 		border-radius 50% | ||||
|  | ||||
| 		animation progress-spinner 400ms linear infinite | ||||
|   | ||||
| @@ -10,7 +10,8 @@ export default Vue.extend({ | ||||
| 	computed: { | ||||
| 		keymap(): any { | ||||
| 			return { | ||||
| 				'h|slash': this.help | ||||
| 				'h|slash': this.help, | ||||
| 				'd': this.dark | ||||
| 			}; | ||||
| 		} | ||||
| 	}, | ||||
| @@ -18,6 +19,13 @@ export default Vue.extend({ | ||||
| 	methods: { | ||||
| 		help() { | ||||
| 			window.open(`${url}/docs/${lang}/keyboard-shortcut`, '_blank'); | ||||
| 		}, | ||||
|  | ||||
| 		dark() { | ||||
| 			this.$store.commit('device/set', { | ||||
| 				key: 'darkmode', | ||||
| 				value: !this.$store.state.device.darkmode | ||||
| 			}); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
|   | ||||
| @@ -34,9 +34,6 @@ html | ||||
| 		//- FontAwesome style | ||||
| 		style #{facss} | ||||
|  | ||||
| 		//- highlight.js style | ||||
| 		style #{hljscss} | ||||
|  | ||||
| 	body | ||||
| 		noscript: p | ||||
| 			| JavaScriptを有効にしてください | ||||
|   | ||||
| @@ -20,6 +20,15 @@ | ||||
|  | ||||
| 	const langs = LANGS; | ||||
|  | ||||
| 	//#region Apply theme | ||||
| 	const theme = localStorage.getItem('theme'); | ||||
| 	if (theme) { | ||||
| 		Object.entries(JSON.parse(theme)).forEach(([k, v]) => { | ||||
| 			document.documentElement.style.setProperty(`--${k}`, v.toString()); | ||||
| 		}); | ||||
| 	} | ||||
| 	//#endregion | ||||
|  | ||||
| 	//#region Load settings | ||||
| 	let settings = null; | ||||
| 	const vuex = localStorage.getItem('vuex'); | ||||
| @@ -84,13 +93,6 @@ | ||||
| 		app = isMobile ? 'mobile' : 'desktop'; | ||||
| 	} | ||||
|  | ||||
| 	// Dark/Light | ||||
| 	if (settings) { | ||||
| 		if (settings.device.darkmode) { | ||||
| 			document.documentElement.setAttribute('data-darkmode', 'true'); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Script version | ||||
| 	const ver = localStorage.getItem('v') || VERSION; | ||||
|  | ||||
|   | ||||
| @@ -59,7 +59,7 @@ export default { | ||||
|  | ||||
| 				el.dataset.reservedKeys = reservedKeys.map(key => `'${key}'`).join(' '); | ||||
|  | ||||
| 				el._keyHandler = e => { | ||||
| 				el._keyHandler = (e: KeyboardEvent) => { | ||||
| 					const key = e.code.toLowerCase(); | ||||
|  | ||||
| 					const targetReservedKeys = document.activeElement ? ((document.activeElement as any).dataset || {}).reservedKeys || '' : ''; | ||||
| @@ -72,7 +72,8 @@ export default { | ||||
| 							const matched = pattern.which.includes(key) && | ||||
| 								pattern.ctrl == e.ctrlKey && | ||||
| 								pattern.shift == e.shiftKey && | ||||
| 								pattern.alt == e.altKey; | ||||
| 								pattern.alt == e.altKey && | ||||
| 								e.metaKey == false; | ||||
|  | ||||
| 							if (matched) { | ||||
| 								e.preventDefault(); | ||||
|   | ||||
| @@ -13,21 +13,21 @@ type Notification = { | ||||
|  | ||||
| export default function(type, data): Notification { | ||||
| 	switch (type) { | ||||
| 		case 'drive_file_created': | ||||
| 		case 'driveFileCreated': | ||||
| 			return { | ||||
| 				title: '%i18n:common.notification.file-uploaded%', | ||||
| 				body: data.name, | ||||
| 				icon: data.url | ||||
| 			}; | ||||
|  | ||||
| 		case 'unread_messaging_message': | ||||
| 		case 'unreadMessagingMessage': | ||||
| 			return { | ||||
| 				title: '%i18n:common.notification.message-from%'.split("{}")[0] + `${getUserName(data.user)}` + '%i18n:common.notification.message-from%'.split("{}")[1] , | ||||
| 				body: data.text, // TODO: getMessagingMessageSummary(data), | ||||
| 				icon: data.user.avatarUrl | ||||
| 			}; | ||||
|  | ||||
| 		case 'reversi_invited': | ||||
| 		case 'reversiInvited': | ||||
| 			return { | ||||
| 				title: '%i18n:common.notification.reversi-invited%', | ||||
| 				body: '%i18n:common.notification.reversi-invited-by%'.split("{}")[0] + `${getUserName(data.parent)}` + '%i18n:common.notification.reversi-invited-by%'.split("{}")[1], | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| require('fuckadblock'); | ||||
|  | ||||
| declare const fuckAdBlock: any; | ||||
|  | ||||
| export default (os) => { | ||||
| 	require('fuckadblock'); | ||||
|  | ||||
| 	function adBlockDetected() { | ||||
| 		os.apis.dialog({ | ||||
| 			title: '%fa:exclamation-triangle%%i18n:common.adblock.detected%', | ||||
|   | ||||
							
								
								
									
										8
									
								
								src/client/app/common/scripts/get-md5.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/client/app/common/scripts/get-md5.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| const crypto = require('crypto'); | ||||
|  | ||||
| export default (data: ArrayBuffer) => { | ||||
|   const buf = new Buffer(data); | ||||
|   const hash = crypto.createHash("md5"); | ||||
|   hash.update(buf); | ||||
|   return hash.digest("hex"); | ||||
| }; | ||||
							
								
								
									
										124
									
								
								src/client/app/common/scripts/note-subscriber.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								src/client/app/common/scripts/note-subscriber.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,124 @@ | ||||
| import Vue from 'vue'; | ||||
|  | ||||
| export default prop => ({ | ||||
| 	data() { | ||||
| 		return { | ||||
| 			connection: null | ||||
| 		}; | ||||
| 	}, | ||||
|  | ||||
| 	computed: { | ||||
| 		$_ns_note_(): any { | ||||
| 			return this[prop]; | ||||
| 		}, | ||||
|  | ||||
| 		$_ns_isRenote(): boolean { | ||||
| 			return (this.$_ns_note_.renote != null && | ||||
| 				this.$_ns_note_.text == null && | ||||
| 				this.$_ns_note_.fileIds.length == 0 && | ||||
| 				this.$_ns_note_.poll == null); | ||||
| 		}, | ||||
|  | ||||
| 		$_ns_target(): any { | ||||
| 			return this.$_ns_isRenote ? this.$_ns_note_.renote : this.$_ns_note_; | ||||
| 		}, | ||||
| 	}, | ||||
|  | ||||
| 	created() { | ||||
| 		if (this.$store.getters.isSignedIn) { | ||||
| 			this.connection = (this as any).os.stream; | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	mounted() { | ||||
| 		this.capture(true); | ||||
|  | ||||
| 		if (this.$store.getters.isSignedIn) { | ||||
| 			this.connection.on('_connected_', this.onStreamConnected); | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	beforeDestroy() { | ||||
| 		this.decapture(true); | ||||
|  | ||||
| 		if (this.$store.getters.isSignedIn) { | ||||
| 			this.connection.off('_connected_', this.onStreamConnected); | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	methods: { | ||||
| 		capture(withHandler = false) { | ||||
| 			if (this.$store.getters.isSignedIn) { | ||||
| 				const data = { | ||||
| 					id: this.$_ns_target.id | ||||
| 				} as any; | ||||
|  | ||||
| 				if ( | ||||
| 					(this.$_ns_target.visibleUserIds || []).includes(this.$store.state.i.id) || | ||||
| 					(this.$_ns_target.mentions || []).includes(this.$store.state.i.id) | ||||
| 				) { | ||||
| 					data.read = true; | ||||
| 				} | ||||
|  | ||||
| 				this.connection.send('sn', data); | ||||
| 				if (withHandler) this.connection.on('noteUpdated', this.onStreamNoteUpdated); | ||||
| 			} | ||||
| 		}, | ||||
|  | ||||
| 		decapture(withHandler = false) { | ||||
| 			if (this.$store.getters.isSignedIn) { | ||||
| 				this.connection.send('un', { | ||||
| 					id: this.$_ns_target.id | ||||
| 				}); | ||||
| 				if (withHandler) this.connection.off('noteUpdated', this.onStreamNoteUpdated); | ||||
| 			} | ||||
| 		}, | ||||
|  | ||||
| 		onStreamConnected() { | ||||
| 			this.capture(); | ||||
| 		}, | ||||
|  | ||||
| 		onStreamNoteUpdated(data) { | ||||
| 			const { type, id, body } = data; | ||||
|  | ||||
| 			if (id !== this.$_ns_target.id) return; | ||||
|  | ||||
| 			switch (type) { | ||||
| 				case 'reacted': { | ||||
| 					const reaction = body.reaction; | ||||
|  | ||||
| 					if (this.$_ns_target.reactionCounts == null) { | ||||
| 						Vue.set(this.$_ns_target, 'reactionCounts', {}); | ||||
| 					} | ||||
|  | ||||
| 					this.$_ns_target.reactionCounts[reaction] = (this.$_ns_target.reactionCounts[reaction] || 0) + 1; | ||||
|  | ||||
| 					if (body.userId == this.$store.state.i.id) { | ||||
| 						Vue.set(this.$_ns_target, 'myReaction', reaction); | ||||
| 					} | ||||
| 					break; | ||||
| 				} | ||||
|  | ||||
| 				case 'pollVoted': { | ||||
| 					if (body.userId == this.$store.state.i.id) return; | ||||
| 					const choice = body.choice; | ||||
| 					this.$_ns_target.poll.choices.find(c => c.id === choice).votes++; | ||||
| 					break; | ||||
| 				} | ||||
|  | ||||
| 				case 'deleted': { | ||||
| 					Vue.set(this.$_ns_target, 'deletedAt', body.deletedAt); | ||||
| 					this.$_ns_target.text = null; | ||||
| 					this.$_ns_target.tags = []; | ||||
| 					this.$_ns_target.fileIds = []; | ||||
| 					this.$_ns_target.poll = null; | ||||
| 					this.$_ns_target.geo = null; | ||||
| 					this.$_ns_target.cw = null; | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			this.$emit(`update:${prop}`, this.$_ns_note_); | ||||
| 		}, | ||||
| 	} | ||||
| }); | ||||
							
								
								
									
										317
									
								
								src/client/app/common/scripts/stream.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										317
									
								
								src/client/app/common/scripts/stream.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,317 @@ | ||||
| import autobind from 'autobind-decorator'; | ||||
| import { EventEmitter } from 'eventemitter3'; | ||||
| import ReconnectingWebsocket from 'reconnecting-websocket'; | ||||
| import { wsUrl } from '../../config'; | ||||
| import MiOS from '../../mios'; | ||||
|  | ||||
| /** | ||||
|  * Misskey stream connection | ||||
|  */ | ||||
| export default class Stream extends EventEmitter { | ||||
| 	private stream: ReconnectingWebsocket; | ||||
| 	private state: string; | ||||
| 	private buffer: any[]; | ||||
| 	private sharedConnections: SharedConnection[] = []; | ||||
| 	private nonSharedConnections: NonSharedConnection[] = []; | ||||
|  | ||||
| 	constructor(os: MiOS) { | ||||
| 		super(); | ||||
|  | ||||
| 		this.state = 'initializing'; | ||||
| 		this.buffer = []; | ||||
|  | ||||
| 		const user = os.store.state.i; | ||||
|  | ||||
| 		this.stream = new ReconnectingWebsocket(wsUrl + (user ? `?i=${user.token}` : '')); | ||||
| 		this.stream.addEventListener('open', this.onOpen); | ||||
| 		this.stream.addEventListener('close', this.onClose); | ||||
| 		this.stream.addEventListener('message', this.onMessage); | ||||
|  | ||||
| 		if (user) { | ||||
| 			const main = this.useSharedConnection('main'); | ||||
|  | ||||
| 			// 自分の情報が更新されたとき | ||||
| 			main.on('meUpdated', i => { | ||||
| 				os.store.dispatch('mergeMe', i); | ||||
| 			}); | ||||
|  | ||||
| 			main.on('readAllNotifications', () => { | ||||
| 				os.store.dispatch('mergeMe', { | ||||
| 					hasUnreadNotification: false | ||||
| 				}); | ||||
| 			}); | ||||
|  | ||||
| 			main.on('unreadNotification', () => { | ||||
| 				os.store.dispatch('mergeMe', { | ||||
| 					hasUnreadNotification: true | ||||
| 				}); | ||||
| 			}); | ||||
|  | ||||
| 			main.on('readAllMessagingMessages', () => { | ||||
| 				os.store.dispatch('mergeMe', { | ||||
| 					hasUnreadMessagingMessage: false | ||||
| 				}); | ||||
| 			}); | ||||
|  | ||||
| 			main.on('unreadMessagingMessage', () => { | ||||
| 				os.store.dispatch('mergeMe', { | ||||
| 					hasUnreadMessagingMessage: true | ||||
| 				}); | ||||
| 			}); | ||||
|  | ||||
| 			main.on('unreadMention', () => { | ||||
| 				os.store.dispatch('mergeMe', { | ||||
| 					hasUnreadMentions: true | ||||
| 				}); | ||||
| 			}); | ||||
|  | ||||
| 			main.on('readAllUnreadMentions', () => { | ||||
| 				os.store.dispatch('mergeMe', { | ||||
| 					hasUnreadMentions: false | ||||
| 				}); | ||||
| 			}); | ||||
|  | ||||
| 			main.on('unreadSpecifiedNote', () => { | ||||
| 				os.store.dispatch('mergeMe', { | ||||
| 					hasUnreadSpecifiedNotes: true | ||||
| 				}); | ||||
| 			}); | ||||
|  | ||||
| 			main.on('readAllUnreadSpecifiedNotes', () => { | ||||
| 				os.store.dispatch('mergeMe', { | ||||
| 					hasUnreadSpecifiedNotes: false | ||||
| 				}); | ||||
| 			}); | ||||
|  | ||||
| 			main.on('clientSettingUpdated', x => { | ||||
| 				os.store.commit('settings/set', { | ||||
| 					key: x.key, | ||||
| 					value: x.value | ||||
| 				}); | ||||
| 			}); | ||||
|  | ||||
| 			main.on('homeUpdated', x => { | ||||
| 				os.store.commit('settings/setHome', x); | ||||
| 			}); | ||||
|  | ||||
| 			main.on('mobileHomeUpdated', x => { | ||||
| 				os.store.commit('settings/setMobileHome', x); | ||||
| 			}); | ||||
|  | ||||
| 			main.on('widgetUpdated', x => { | ||||
| 				os.store.commit('settings/setWidget', { | ||||
| 					id: x.id, | ||||
| 					data: x.data | ||||
| 				}); | ||||
| 			}); | ||||
|  | ||||
| 			// トークンが再生成されたとき | ||||
| 			// このままではMisskeyが利用できないので強制的にサインアウトさせる | ||||
| 			main.on('myTokenRegenerated', () => { | ||||
| 				alert('%i18n:common.my-token-regenerated%'); | ||||
| 				os.signout(); | ||||
| 			}); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public useSharedConnection = (channel: string): SharedConnection => { | ||||
| 		const existConnection = this.sharedConnections.find(c => c.channel === channel); | ||||
|  | ||||
| 		if (existConnection) { | ||||
| 			existConnection.use(); | ||||
| 			return existConnection; | ||||
| 		} else { | ||||
| 			const connection = new SharedConnection(this, channel); | ||||
| 			connection.use(); | ||||
| 			this.sharedConnections.push(connection); | ||||
| 			return connection; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	public removeSharedConnection(connection: SharedConnection) { | ||||
| 		this.sharedConnections = this.sharedConnections.filter(c => c.id !== connection.id); | ||||
| 	} | ||||
|  | ||||
| 	public connectToChannel = (channel: string, params?: any): NonSharedConnection => { | ||||
| 		const connection = new NonSharedConnection(this, channel, params); | ||||
| 		this.nonSharedConnections.push(connection); | ||||
| 		return connection; | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	public disconnectToChannel(connection: NonSharedConnection) { | ||||
| 		this.nonSharedConnections = this.nonSharedConnections.filter(c => c.id !== connection.id); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Callback of when open connection | ||||
| 	 */ | ||||
| 	@autobind | ||||
| 	private onOpen() { | ||||
| 		const isReconnect = this.state == 'reconnecting'; | ||||
|  | ||||
| 		this.state = 'connected'; | ||||
| 		this.emit('_connected_'); | ||||
|  | ||||
| 		// バッファーを処理 | ||||
| 		const _buffer = [].concat(this.buffer); // Shallow copy | ||||
| 		this.buffer = []; // Clear buffer | ||||
| 		_buffer.forEach(data => { | ||||
| 			this.send(data); // Resend each buffered messages | ||||
| 		}); | ||||
|  | ||||
| 		// チャンネル再接続 | ||||
| 		if (isReconnect) { | ||||
| 			this.sharedConnections.forEach(c => { | ||||
| 				c.connect(); | ||||
| 			}); | ||||
| 			this.nonSharedConnections.forEach(c => { | ||||
| 				c.connect(); | ||||
| 			}); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Callback of when close connection | ||||
| 	 */ | ||||
| 	@autobind | ||||
| 	private onClose() { | ||||
| 		this.state = 'reconnecting'; | ||||
| 		this.emit('_disconnected_'); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Callback of when received a message from connection | ||||
| 	 */ | ||||
| 	@autobind | ||||
| 	private onMessage(message) { | ||||
| 		const { type, body } = JSON.parse(message.data); | ||||
|  | ||||
| 		if (type == 'channel') { | ||||
| 			const id = body.id; | ||||
| 			const connection = this.sharedConnections.find(c => c.id === id) || this.nonSharedConnections.find(c => c.id === id); | ||||
| 			connection.emit(body.type, body.body); | ||||
| 		} else { | ||||
| 			this.emit(type, body); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Send a message to connection | ||||
| 	 */ | ||||
| 	@autobind | ||||
| 	public send(typeOrPayload, payload?) { | ||||
| 		const data = payload === undefined ? typeOrPayload : { | ||||
| 			type: typeOrPayload, | ||||
| 			body: payload | ||||
| 		}; | ||||
|  | ||||
| 		// まだ接続が確立されていなかったらバッファリングして次に接続した時に送信する | ||||
| 		if (this.state != 'connected') { | ||||
| 			this.buffer.push(data); | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		this.stream.send(JSON.stringify(data)); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Close this connection | ||||
| 	 */ | ||||
| 	@autobind | ||||
| 	public close() { | ||||
| 		this.stream.removeEventListener('open', this.onOpen); | ||||
| 		this.stream.removeEventListener('message', this.onMessage); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| abstract class Connection extends EventEmitter { | ||||
| 	public channel: string; | ||||
| 	public id: string; | ||||
| 	protected params: any; | ||||
| 	protected stream: Stream; | ||||
|  | ||||
| 	constructor(stream: Stream, channel: string, params?: any) { | ||||
| 		super(); | ||||
|  | ||||
| 		this.stream = stream; | ||||
| 		this.channel = channel; | ||||
| 		this.params = params; | ||||
| 		this.id = Math.random().toString(); | ||||
| 		this.connect(); | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	public connect() { | ||||
| 		this.stream.send('connect', { | ||||
| 			channel: this.channel, | ||||
| 			id: this.id, | ||||
| 			params: this.params | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	public send(typeOrPayload, payload?) { | ||||
| 		const type = payload === undefined ? typeOrPayload.type : typeOrPayload; | ||||
| 		const body = payload === undefined ? typeOrPayload.body : payload; | ||||
|  | ||||
| 		this.stream.send('channel', { | ||||
| 			id: this.id, | ||||
| 			type: type, | ||||
| 			body: body | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	public abstract dispose: () => void; | ||||
| } | ||||
|  | ||||
| class SharedConnection extends Connection { | ||||
| 	private users = 0; | ||||
| 	private disposeTimerId: any; | ||||
|  | ||||
| 	constructor(stream: Stream, channel: string) { | ||||
| 		super(stream, channel); | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	public use() { | ||||
| 		this.users++; | ||||
|  | ||||
| 		// タイマー解除 | ||||
| 		if (this.disposeTimerId) { | ||||
| 			clearTimeout(this.disposeTimerId); | ||||
| 			this.disposeTimerId = null; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	public dispose() { | ||||
| 		this.users--; | ||||
|  | ||||
| 		// そのコネクションの利用者が誰もいなくなったら | ||||
| 		if (this.users === 0) { | ||||
| 			// また直ぐに再利用される可能性があるので、一定時間待ち、 | ||||
| 			// 新たな利用者が現れなければコネクションを切断する | ||||
| 			this.disposeTimerId = setTimeout(() => { | ||||
| 				this.disposeTimerId = null; | ||||
| 				this.removeAllListeners(); | ||||
| 				this.stream.send('disconnect', { id: this.id }); | ||||
| 				this.stream.removeSharedConnection(this); | ||||
| 			}, 3000); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| class NonSharedConnection extends Connection { | ||||
| 	constructor(stream: Stream, channel: string, params?: any) { | ||||
| 		super(stream, channel, params); | ||||
| 	} | ||||
|  | ||||
| 	@autobind | ||||
| 	public dispose() { | ||||
| 		this.removeAllListeners(); | ||||
| 		this.stream.send('disconnect', { id: this.id }); | ||||
| 		this.stream.disconnectToChannel(this); | ||||
| 	} | ||||
| } | ||||
| @@ -1,34 +0,0 @@ | ||||
| import Stream from './stream'; | ||||
| import StreamManager from './stream-manager'; | ||||
| import MiOS from '../../../mios'; | ||||
|  | ||||
| /** | ||||
|  * Drive stream connection | ||||
|  */ | ||||
| export class DriveStream extends Stream { | ||||
| 	constructor(os: MiOS, me) { | ||||
| 		super(os, 'drive', { | ||||
| 			i: me.token | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export class DriveStreamManager extends StreamManager<DriveStream> { | ||||
| 	private me; | ||||
| 	private os: MiOS; | ||||
|  | ||||
| 	constructor(os: MiOS, me) { | ||||
| 		super(); | ||||
|  | ||||
| 		this.me = me; | ||||
| 		this.os = os; | ||||
| 	} | ||||
|  | ||||
| 	public getConnection() { | ||||
| 		if (this.connection == null) { | ||||
| 			this.connection = new DriveStream(this.os, this.me); | ||||
| 		} | ||||
|  | ||||
| 		return this.connection; | ||||
| 	} | ||||
| } | ||||
| @@ -1,13 +0,0 @@ | ||||
| import Stream from '../../stream'; | ||||
| import MiOS from '../../../../../mios'; | ||||
|  | ||||
| export class ReversiGameStream extends Stream { | ||||
| 	constructor(os: MiOS, me, game) { | ||||
| 		super(os, 'games/reversi-game', me ? { | ||||
| 			i: me.token, | ||||
| 			game: game.id | ||||
| 		} : { | ||||
| 			game: game.id | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
| @@ -1,31 +0,0 @@ | ||||
| import StreamManager from '../../stream-manager'; | ||||
| import Stream from '../../stream'; | ||||
| import MiOS from '../../../../../mios'; | ||||
|  | ||||
| export class ReversiStream extends Stream { | ||||
| 	constructor(os: MiOS, me) { | ||||
| 		super(os, 'games/reversi', { | ||||
| 			i: me.token | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export class ReversiStreamManager extends StreamManager<ReversiStream> { | ||||
| 	private me; | ||||
| 	private os: MiOS; | ||||
|  | ||||
| 	constructor(os: MiOS, me) { | ||||
| 		super(); | ||||
|  | ||||
| 		this.me = me; | ||||
| 		this.os = os; | ||||
| 	} | ||||
|  | ||||
| 	public getConnection() { | ||||
| 		if (this.connection == null) { | ||||
| 			this.connection = new ReversiStream(this.os, this.me); | ||||
| 		} | ||||
|  | ||||
| 		return this.connection; | ||||
| 	} | ||||
| } | ||||
| @@ -1,34 +0,0 @@ | ||||
| import Stream from './stream'; | ||||
| import StreamManager from './stream-manager'; | ||||
| import MiOS from '../../../mios'; | ||||
|  | ||||
| /** | ||||
|  * Global timeline stream connection | ||||
|  */ | ||||
| export class GlobalTimelineStream extends Stream { | ||||
| 	constructor(os: MiOS, me) { | ||||
| 		super(os, 'global-timeline', { | ||||
| 			i: me.token | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export class GlobalTimelineStreamManager extends StreamManager<GlobalTimelineStream> { | ||||
| 	private me; | ||||
| 	private os: MiOS; | ||||
|  | ||||
| 	constructor(os: MiOS, me) { | ||||
| 		super(); | ||||
|  | ||||
| 		this.me = me; | ||||
| 		this.os = os; | ||||
| 	} | ||||
|  | ||||
| 	public getConnection() { | ||||
| 		if (this.connection == null) { | ||||
| 			this.connection = new GlobalTimelineStream(this.os, this.me); | ||||
| 		} | ||||
|  | ||||
| 		return this.connection; | ||||
| 	} | ||||
| } | ||||
| @@ -1,13 +0,0 @@ | ||||
| import Stream from './stream'; | ||||
| import MiOS from '../../../mios'; | ||||
|  | ||||
| export class HashtagStream extends Stream { | ||||
| 	constructor(os: MiOS, me, q) { | ||||
| 		super(os, 'hashtag', me ? { | ||||
| 			i: me.token, | ||||
| 			q: JSON.stringify(q) | ||||
| 		} : { | ||||
| 			q: JSON.stringify(q) | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
| @@ -1,126 +0,0 @@ | ||||
| import Stream from './stream'; | ||||
| import StreamManager from './stream-manager'; | ||||
| import MiOS from '../../../mios'; | ||||
|  | ||||
| /** | ||||
|  * Home stream connection | ||||
|  */ | ||||
| export class HomeStream extends Stream { | ||||
| 	constructor(os: MiOS, me) { | ||||
| 		super(os, '', { | ||||
| 			i: me.token | ||||
| 		}); | ||||
|  | ||||
| 		// 最終利用日時を更新するため定期的にaliveメッセージを送信 | ||||
| 		setInterval(() => { | ||||
| 			this.send({ type: 'alive' }); | ||||
| 			me.lastUsedAt = new Date(); | ||||
| 		}, 1000 * 60); | ||||
|  | ||||
| 		// 自分の情報が更新されたとき | ||||
| 		this.on('meUpdated', i => { | ||||
| 			if (os.debug) { | ||||
| 				console.log('I updated:', i); | ||||
| 			} | ||||
|  | ||||
| 			os.store.dispatch('mergeMe', i); | ||||
| 		}); | ||||
|  | ||||
| 		this.on('read_all_notifications', () => { | ||||
| 			os.store.dispatch('mergeMe', { | ||||
| 				hasUnreadNotification: false | ||||
| 			}); | ||||
| 		}); | ||||
|  | ||||
| 		this.on('unread_notification', () => { | ||||
| 			os.store.dispatch('mergeMe', { | ||||
| 				hasUnreadNotification: true | ||||
| 			}); | ||||
| 		}); | ||||
|  | ||||
| 		this.on('read_all_messaging_messages', () => { | ||||
| 			os.store.dispatch('mergeMe', { | ||||
| 				hasUnreadMessagingMessage: false | ||||
| 			}); | ||||
| 		}); | ||||
|  | ||||
| 		this.on('unread_messaging_message', () => { | ||||
| 			os.store.dispatch('mergeMe', { | ||||
| 				hasUnreadMessagingMessage: true | ||||
| 			}); | ||||
| 		}); | ||||
|  | ||||
| 		this.on('unreadMention', () => { | ||||
| 			os.store.dispatch('mergeMe', { | ||||
| 				hasUnreadMentions: true | ||||
| 			}); | ||||
| 		}); | ||||
|  | ||||
| 		this.on('readAllUnreadMentions', () => { | ||||
| 			os.store.dispatch('mergeMe', { | ||||
| 				hasUnreadMentions: false | ||||
| 			}); | ||||
| 		}); | ||||
|  | ||||
| 		this.on('unreadSpecifiedNote', () => { | ||||
| 			os.store.dispatch('mergeMe', { | ||||
| 				hasUnreadSpecifiedNotes: true | ||||
| 			}); | ||||
| 		}); | ||||
|  | ||||
| 		this.on('readAllUnreadSpecifiedNotes', () => { | ||||
| 			os.store.dispatch('mergeMe', { | ||||
| 				hasUnreadSpecifiedNotes: false | ||||
| 			}); | ||||
| 		}); | ||||
|  | ||||
| 		this.on('clientSettingUpdated', x => { | ||||
| 			os.store.commit('settings/set', { | ||||
| 				key: x.key, | ||||
| 				value: x.value | ||||
| 			}); | ||||
| 		}); | ||||
|  | ||||
| 		this.on('home_updated', x => { | ||||
| 			os.store.commit('settings/setHome', x); | ||||
| 		}); | ||||
|  | ||||
| 		this.on('mobile_home_updated', x => { | ||||
| 			os.store.commit('settings/setMobileHome', x); | ||||
| 		}); | ||||
|  | ||||
| 		this.on('widgetUpdated', x => { | ||||
| 			os.store.commit('settings/setWidget', { | ||||
| 				id: x.id, | ||||
| 				data: x.data | ||||
| 			}); | ||||
| 		}); | ||||
|  | ||||
| 		// トークンが再生成されたとき | ||||
| 		// このままではMisskeyが利用できないので強制的にサインアウトさせる | ||||
| 		this.on('my_token_regenerated', () => { | ||||
| 			alert('%i18n:common.my-token-regenerated%'); | ||||
| 			os.signout(); | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export class HomeStreamManager extends StreamManager<HomeStream> { | ||||
| 	private me; | ||||
| 	private os: MiOS; | ||||
|  | ||||
| 	constructor(os: MiOS, me) { | ||||
| 		super(); | ||||
|  | ||||
| 		this.me = me; | ||||
| 		this.os = os; | ||||
| 	} | ||||
|  | ||||
| 	public getConnection() { | ||||
| 		if (this.connection == null) { | ||||
| 			this.connection = new HomeStream(this.os, this.me); | ||||
| 		} | ||||
|  | ||||
| 		return this.connection; | ||||
| 	} | ||||
| } | ||||
| @@ -1,34 +0,0 @@ | ||||
| import Stream from './stream'; | ||||
| import StreamManager from './stream-manager'; | ||||
| import MiOS from '../../../mios'; | ||||
|  | ||||
| /** | ||||
|  * Hybrid timeline stream connection | ||||
|  */ | ||||
| export class HybridTimelineStream extends Stream { | ||||
| 	constructor(os: MiOS, me) { | ||||
| 		super(os, 'hybrid-timeline', { | ||||
| 			i: me.token | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export class HybridTimelineStreamManager extends StreamManager<HybridTimelineStream> { | ||||
| 	private me; | ||||
| 	private os: MiOS; | ||||
|  | ||||
| 	constructor(os: MiOS, me) { | ||||
| 		super(); | ||||
|  | ||||
| 		this.me = me; | ||||
| 		this.os = os; | ||||
| 	} | ||||
|  | ||||
| 	public getConnection() { | ||||
| 		if (this.connection == null) { | ||||
| 			this.connection = new HybridTimelineStream(this.os, this.me); | ||||
| 		} | ||||
|  | ||||
| 		return this.connection; | ||||
| 	} | ||||
| } | ||||
| @@ -1,34 +0,0 @@ | ||||
| import Stream from './stream'; | ||||
| import StreamManager from './stream-manager'; | ||||
| import MiOS from '../../../mios'; | ||||
|  | ||||
| /** | ||||
|  * Local timeline stream connection | ||||
|  */ | ||||
| export class LocalTimelineStream extends Stream { | ||||
| 	constructor(os: MiOS, me) { | ||||
| 		super(os, 'local-timeline', me ? { | ||||
| 			i: me.token | ||||
| 		} : {}); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export class LocalTimelineStreamManager extends StreamManager<LocalTimelineStream> { | ||||
| 	private me; | ||||
| 	private os: MiOS; | ||||
|  | ||||
| 	constructor(os: MiOS, me) { | ||||
| 		super(); | ||||
|  | ||||
| 		this.me = me; | ||||
| 		this.os = os; | ||||
| 	} | ||||
|  | ||||
| 	public getConnection() { | ||||
| 		if (this.connection == null) { | ||||
| 			this.connection = new LocalTimelineStream(this.os, this.me); | ||||
| 		} | ||||
|  | ||||
| 		return this.connection; | ||||
| 	} | ||||
| } | ||||
| @@ -1,34 +0,0 @@ | ||||
| import Stream from './stream'; | ||||
| import StreamManager from './stream-manager'; | ||||
| import MiOS from '../../../mios'; | ||||
|  | ||||
| /** | ||||
|  * Messaging index stream connection | ||||
|  */ | ||||
| export class MessagingIndexStream extends Stream { | ||||
| 	constructor(os: MiOS, me) { | ||||
| 		super(os, 'messaging-index', { | ||||
| 			i: me.token | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export class MessagingIndexStreamManager extends StreamManager<MessagingIndexStream> { | ||||
| 	private me; | ||||
| 	private os: MiOS; | ||||
|  | ||||
| 	constructor(os: MiOS, me) { | ||||
| 		super(); | ||||
|  | ||||
| 		this.me = me; | ||||
| 		this.os = os; | ||||
| 	} | ||||
|  | ||||
| 	public getConnection() { | ||||
| 		if (this.connection == null) { | ||||
| 			this.connection = new MessagingIndexStream(this.os, this.me); | ||||
| 		} | ||||
|  | ||||
| 		return this.connection; | ||||
| 	} | ||||
| } | ||||
| @@ -1,20 +0,0 @@ | ||||
| import Stream from './stream'; | ||||
| import MiOS from '../../../mios'; | ||||
|  | ||||
| /** | ||||
|  * Messaging stream connection | ||||
|  */ | ||||
| export class MessagingStream extends Stream { | ||||
| 	constructor(os: MiOS, me, otherparty) { | ||||
| 		super(os, 'messaging', { | ||||
| 			i: me.token, | ||||
| 			otherparty | ||||
| 		}); | ||||
|  | ||||
| 		(this as any).on('_connected_', () => { | ||||
| 			this.send({ | ||||
| 				i: me.token | ||||
| 			}); | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
| @@ -1,30 +0,0 @@ | ||||
| import Stream from './stream'; | ||||
| import StreamManager from './stream-manager'; | ||||
| import MiOS from '../../../mios'; | ||||
|  | ||||
| /** | ||||
|  * Notes stats stream connection | ||||
|  */ | ||||
| export class NotesStatsStream extends Stream { | ||||
| 	constructor(os: MiOS) { | ||||
| 		super(os, 'notes-stats'); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export class NotesStatsStreamManager extends StreamManager<NotesStatsStream> { | ||||
| 	private os: MiOS; | ||||
|  | ||||
| 	constructor(os: MiOS) { | ||||
| 		super(); | ||||
|  | ||||
| 		this.os = os; | ||||
| 	} | ||||
|  | ||||
| 	public getConnection() { | ||||
| 		if (this.connection == null) { | ||||
| 			this.connection = new NotesStatsStream(this.os); | ||||
| 		} | ||||
|  | ||||
| 		return this.connection; | ||||
| 	} | ||||
| } | ||||
| @@ -1,30 +0,0 @@ | ||||
| import Stream from './stream'; | ||||
| import StreamManager from './stream-manager'; | ||||
| import MiOS from '../../../mios'; | ||||
|  | ||||
| /** | ||||
|  * Server stats stream connection | ||||
|  */ | ||||
| export class ServerStatsStream extends Stream { | ||||
| 	constructor(os: MiOS) { | ||||
| 		super(os, 'server-stats'); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export class ServerStatsStreamManager extends StreamManager<ServerStatsStream> { | ||||
| 	private os: MiOS; | ||||
|  | ||||
| 	constructor(os: MiOS) { | ||||
| 		super(); | ||||
|  | ||||
| 		this.os = os; | ||||
| 	} | ||||
|  | ||||
| 	public getConnection() { | ||||
| 		if (this.connection == null) { | ||||
| 			this.connection = new ServerStatsStream(this.os); | ||||
| 		} | ||||
|  | ||||
| 		return this.connection; | ||||
| 	} | ||||
| } | ||||
| @@ -1,109 +0,0 @@ | ||||
| import { EventEmitter } from 'eventemitter3'; | ||||
| import * as uuid from 'uuid'; | ||||
| import Connection from './stream'; | ||||
| import { erase } from '../../../../../prelude/array'; | ||||
|  | ||||
| /** | ||||
|  * ストリーム接続を管理するクラス | ||||
|  * 複数の場所から同じストリームを利用する際、接続をまとめたりする | ||||
|  */ | ||||
| export default abstract class StreamManager<T extends Connection> extends EventEmitter { | ||||
| 	private _connection: T = null; | ||||
|  | ||||
| 	private disposeTimerId: any; | ||||
|  | ||||
| 	/** | ||||
| 	 * コネクションを必要としているユーザー | ||||
| 	 */ | ||||
| 	private users = []; | ||||
|  | ||||
| 	protected set connection(connection: T) { | ||||
| 		this._connection = connection; | ||||
|  | ||||
| 		if (this._connection == null) { | ||||
| 			this.emit('disconnected'); | ||||
| 		} else { | ||||
| 			this.emit('connected', this._connection); | ||||
|  | ||||
| 			this._connection.on('_connected_', () => { | ||||
| 				this.emit('_connected_'); | ||||
| 			}); | ||||
|  | ||||
| 			this._connection.on('_disconnected_', () => { | ||||
| 				this.emit('_disconnected_'); | ||||
| 			}); | ||||
|  | ||||
| 			this._connection.user = 'Managed'; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	protected get connection() { | ||||
| 		return this._connection; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * コネクションを持っているか否か | ||||
| 	 */ | ||||
| 	public get hasConnection() { | ||||
| 		return this._connection != null; | ||||
| 	} | ||||
|  | ||||
| 	public get state(): string { | ||||
| 		if (!this.hasConnection) return 'no-connection'; | ||||
| 		return this._connection.state; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * コネクションを要求します | ||||
| 	 */ | ||||
| 	public abstract getConnection(): T; | ||||
|  | ||||
| 	/** | ||||
| 	 * 現在接続しているコネクションを取得します | ||||
| 	 */ | ||||
| 	public borrow() { | ||||
| 		return this._connection; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * コネクションを要求するためのユーザーIDを発行します | ||||
| 	 */ | ||||
| 	public use() { | ||||
| 		// タイマー解除 | ||||
| 		if (this.disposeTimerId) { | ||||
| 			clearTimeout(this.disposeTimerId); | ||||
| 			this.disposeTimerId = null; | ||||
| 		} | ||||
|  | ||||
| 		// ユーザーID生成 | ||||
| 		const userId = uuid(); | ||||
|  | ||||
| 		this.users.push(userId); | ||||
|  | ||||
| 		this._connection.user = `Managed (${ this.users.length })`; | ||||
|  | ||||
| 		return userId; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * コネクションを利用し終わってもう必要ないことを通知します | ||||
| 	 * @param userId use で発行したユーザーID | ||||
| 	 */ | ||||
| 	public dispose(userId) { | ||||
| 		this.users = erase(userId, this.users); | ||||
|  | ||||
| 		this._connection.user = `Managed (${ this.users.length })`; | ||||
|  | ||||
| 		// 誰もコネクションの利用者がいなくなったら | ||||
| 		if (this.users.length == 0) { | ||||
| 			// また直ぐに再利用される可能性があるので、一定時間待ち、 | ||||
| 			// 新たな利用者が現れなければコネクションを切断する | ||||
| 			this.disposeTimerId = setTimeout(() => { | ||||
| 				this.disposeTimerId = null; | ||||
|  | ||||
| 				this.connection.close(); | ||||
| 				this.connection = null; | ||||
| 			}, 3000); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -1,137 +0,0 @@ | ||||
| import { EventEmitter } from 'eventemitter3'; | ||||
| import * as uuid from 'uuid'; | ||||
| import * as ReconnectingWebsocket from 'reconnecting-websocket'; | ||||
| import { wsUrl } from '../../../config'; | ||||
| import MiOS from '../../../mios'; | ||||
|  | ||||
| /** | ||||
|  * Misskey stream connection | ||||
|  */ | ||||
| export default class Connection extends EventEmitter { | ||||
| 	public state: string; | ||||
| 	private buffer: any[]; | ||||
| 	public socket: ReconnectingWebsocket; | ||||
| 	public name: string; | ||||
| 	public connectedAt: Date; | ||||
| 	public user: string = null; | ||||
| 	public in: number = 0; | ||||
| 	public out: number = 0; | ||||
| 	public inout: Array<{ | ||||
| 		type: 'in' | 'out', | ||||
| 		at: Date, | ||||
| 		data: string | ||||
| 	}> = []; | ||||
| 	public id: string; | ||||
| 	public isSuspended = false; | ||||
| 	private os: MiOS; | ||||
|  | ||||
| 	constructor(os: MiOS, endpoint, params?) { | ||||
| 		super(); | ||||
|  | ||||
| 		//#region BIND | ||||
| 		this.onOpen =    this.onOpen.bind(this); | ||||
| 		this.onClose =   this.onClose.bind(this); | ||||
| 		this.onMessage = this.onMessage.bind(this); | ||||
| 		this.send =      this.send.bind(this); | ||||
| 		this.close =     this.close.bind(this); | ||||
| 		//#endregion | ||||
|  | ||||
| 		this.id = uuid(); | ||||
| 		this.os = os; | ||||
| 		this.name = endpoint; | ||||
| 		this.state = 'initializing'; | ||||
| 		this.buffer = []; | ||||
|  | ||||
| 		const query = params | ||||
| 			? Object.keys(params) | ||||
| 				.map(k => `${encodeURIComponent(k)}=${encodeURIComponent(params[k])}`) | ||||
| 				.join('&') | ||||
| 			: null; | ||||
|  | ||||
| 		this.socket = new ReconnectingWebsocket(`${wsUrl}/${endpoint}${query ? `?${query}` : ''}`); | ||||
| 		this.socket.addEventListener('open', this.onOpen); | ||||
| 		this.socket.addEventListener('close', this.onClose); | ||||
| 		this.socket.addEventListener('message', this.onMessage); | ||||
|  | ||||
| 		// Register this connection for debugging | ||||
| 		this.os.registerStreamConnection(this); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Callback of when open connection | ||||
| 	 */ | ||||
| 	private onOpen() { | ||||
| 		this.state = 'connected'; | ||||
| 		this.emit('_connected_'); | ||||
|  | ||||
| 		this.connectedAt = new Date(); | ||||
|  | ||||
| 		// バッファーを処理 | ||||
| 		const _buffer = [].concat(this.buffer); // Shallow copy | ||||
| 		this.buffer = []; // Clear buffer | ||||
| 		_buffer.forEach(data => { | ||||
| 			this.send(data); // Resend each buffered messages | ||||
|  | ||||
| 			if (this.os.debug) { | ||||
| 				this.out++; | ||||
| 				this.inout.push({ type: 'out', at: new Date(), data }); | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Callback of when close connection | ||||
| 	 */ | ||||
| 	private onClose() { | ||||
| 		this.state = 'reconnecting'; | ||||
| 		this.emit('_disconnected_'); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Callback of when received a message from connection | ||||
| 	 */ | ||||
| 	private onMessage(message) { | ||||
| 		if (this.isSuspended) return; | ||||
|  | ||||
| 		if (this.os.debug) { | ||||
| 			this.in++; | ||||
| 			this.inout.push({ type: 'in', at: new Date(), data: message.data }); | ||||
| 		} | ||||
|  | ||||
| 		try { | ||||
| 			const msg = JSON.parse(message.data); | ||||
| 			if (msg.type) this.emit(msg.type, msg.body); | ||||
| 		} catch (e) { | ||||
| 			// noop | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Send a message to connection | ||||
| 	 */ | ||||
| 	public send(data) { | ||||
| 		if (this.isSuspended) return; | ||||
|  | ||||
| 		// まだ接続が確立されていなかったらバッファリングして次に接続した時に送信する | ||||
| 		if (this.state != 'connected') { | ||||
| 			this.buffer.push(data); | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		if (this.os.debug) { | ||||
| 			this.out++; | ||||
| 			this.inout.push({ type: 'out', at: new Date(), data }); | ||||
| 		} | ||||
|  | ||||
| 		this.socket.send(JSON.stringify(data)); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Close this connection | ||||
| 	 */ | ||||
| 	public close() { | ||||
| 		this.os.unregisterStreamConnection(this); | ||||
| 		this.socket.removeEventListener('open', this.onOpen); | ||||
| 		this.socket.removeEventListener('message', this.onMessage); | ||||
| 	} | ||||
| } | ||||
| @@ -1,17 +0,0 @@ | ||||
| import Stream from './stream'; | ||||
| import MiOS from '../../mios'; | ||||
|  | ||||
| export class UserListStream extends Stream { | ||||
| 	constructor(os: MiOS, me, listId) { | ||||
| 		super(os, 'user-list', { | ||||
| 			i: me.token, | ||||
| 			listId | ||||
| 		}); | ||||
|  | ||||
| 		(this as any).on('_connected_', () => { | ||||
| 			this.send({ | ||||
| 				i: me.token | ||||
| 			}); | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
| @@ -259,15 +259,13 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
| .mk-autocomplete | ||||
| 	position fixed | ||||
| 	z-index 65535 | ||||
| 	max-width 100% | ||||
| 	margin-top calc(1em + 8px) | ||||
| 	overflow hidden | ||||
| 	background isDark ? #313543 : #fff | ||||
| 	background var(--faceHeader) | ||||
| 	border solid 1px rgba(#000, 0.1) | ||||
| 	border-radius 4px | ||||
| 	transition top 0.1s ease, left 0.1s ease | ||||
| @@ -299,16 +297,16 @@ root(isDark) | ||||
| 				text-overflow ellipsis | ||||
|  | ||||
| 			&:hover | ||||
| 				background isDark ? rgba(#fff, 0.1) : rgba(#000, 0.1) | ||||
| 				background var(--autocompleteItemHoverBg) | ||||
|  | ||||
| 			&[data-selected='true'] | ||||
| 				background $theme-color | ||||
| 				background var(--primary) | ||||
|  | ||||
| 				&, * | ||||
| 					color #fff !important | ||||
|  | ||||
| 			&:active | ||||
| 				background darken($theme-color, 10%) | ||||
| 				background var(--primaryDarken10) | ||||
|  | ||||
| 				&, * | ||||
| 					color #fff !important | ||||
| @@ -325,15 +323,15 @@ root(isDark) | ||||
|  | ||||
| 		.name | ||||
| 			margin 0 8px 0 0 | ||||
| 			color isDark ? rgba(#fff, 0.8) : rgba(#000, 0.8) | ||||
| 			color var(--autocompleteItemText) | ||||
|  | ||||
| 		.username | ||||
| 			color isDark ? rgba(#fff, 0.3) : rgba(#000, 0.3) | ||||
| 			color var(--autocompleteItemTextSub) | ||||
|  | ||||
| 	> .hashtags > li | ||||
|  | ||||
| 		.name | ||||
| 			color isDark ? rgba(#fff, 0.8) : rgba(#000, 0.8) | ||||
| 			color var(--autocompleteItemText) | ||||
|  | ||||
| 	> .emojis > li | ||||
|  | ||||
| @@ -343,15 +341,9 @@ root(isDark) | ||||
| 			width 24px | ||||
|  | ||||
| 		.name | ||||
| 			color isDark ? rgba(#fff, 0.8) : rgba(#000, 0.8) | ||||
| 			color var(--autocompleteItemText) | ||||
|  | ||||
| 		.alias | ||||
| 			margin 0 0 0 8px | ||||
| 			color isDark ? rgba(#fff, 0.3) : rgba(#000, 0.3) | ||||
|  | ||||
| .mk-autocomplete[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .mk-autocomplete:not([data-darkmode]) | ||||
| 	root(false) | ||||
| 			color var(--autocompleteItemTextSub) | ||||
| </style> | ||||
|   | ||||
| @@ -58,6 +58,11 @@ export default Vue.extend({ | ||||
| 			}; | ||||
| 		} | ||||
| 	}, | ||||
| 	mounted() { | ||||
| 		if (this.user.avatarColor) { | ||||
| 			this.$el.style.color = `rgb(${this.user.avatarColor.slice(0, 3).join(',')})`; | ||||
| 		} | ||||
| 	}, | ||||
| 	methods: { | ||||
| 		onClick(e) { | ||||
| 			this.$emit('click', e); | ||||
| @@ -67,8 +72,7 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
|  | ||||
| root(isDark) | ||||
| .mk-avatar | ||||
| 	display inline-block | ||||
| 	vertical-align bottom | ||||
|  | ||||
| @@ -79,7 +83,7 @@ root(isDark) | ||||
| 	&.cat::before, | ||||
| 	&.cat::after | ||||
| 		background #df548f | ||||
| 		border solid 4px isDark ? #e0eefd : #202224 | ||||
| 		border solid 4px currentColor | ||||
| 		box-sizing border-box | ||||
| 		content '' | ||||
| 		display inline-block | ||||
| @@ -105,9 +109,4 @@ root(isDark) | ||||
| 		transition border-radius 1s ease | ||||
| 		z-index 1 | ||||
|  | ||||
| .mk-avatar[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .mk-avatar:not([data-darkmode]) | ||||
| 	root(false) | ||||
| </style> | ||||
|   | ||||
| @@ -39,7 +39,7 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
|  | ||||
| .mk-connect-failed | ||||
| 	width 100% | ||||
| @@ -70,17 +70,17 @@ export default Vue.extend({ | ||||
| 		display block | ||||
| 		margin 1em auto 0 auto | ||||
| 		padding 8px 10px | ||||
| 		color $theme-color-foreground | ||||
| 		background $theme-color | ||||
| 		color var(--primaryForeground) | ||||
| 		background var(--primary) | ||||
|  | ||||
| 		&:focus | ||||
| 			outline solid 3px rgba($theme-color, 0.3) | ||||
| 			outline solid 3px var(--primaryAlpha03) | ||||
|  | ||||
| 		&:hover | ||||
| 			background lighten($theme-color, 10%) | ||||
| 			background var(--primaryLighten10) | ||||
|  | ||||
| 		&:active | ||||
| 			background darken($theme-color, 10%) | ||||
| 			background var(--primaryDarken10) | ||||
|  | ||||
| 	> .thanks | ||||
| 		display block | ||||
|   | ||||
| @@ -22,23 +22,17 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| root(isDark) | ||||
| .nrvgflfuaxwgkxoynpnumyookecqrrvh | ||||
| 	display inline-block | ||||
| 	padding 4px 8px | ||||
| 	font-size 0.7em | ||||
| 	color isDark ? #393f4f : #fff | ||||
| 	background isDark ? #687390 : #b1b9c1 | ||||
| 	color var(--cwButtonFg) | ||||
| 	background var(--cwButtonBg) | ||||
| 	border-radius 2px | ||||
| 	cursor pointer | ||||
| 	user-select none | ||||
|  | ||||
| 	&:hover | ||||
| 		background isDark ? #707b97 : #bbc4ce | ||||
|  | ||||
| .nrvgflfuaxwgkxoynpnumyookecqrrvh[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .nrvgflfuaxwgkxoynpnumyookecqrrvh:not([data-darkmode]) | ||||
| 	root(false) | ||||
| 		background var(--cwButtonHoverBg) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -9,7 +9,7 @@ | ||||
| </template> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
|  | ||||
| .a | ||||
| 	display block | ||||
| @@ -18,8 +18,8 @@ | ||||
| 		display block | ||||
| 		//fill #151513 | ||||
| 		//color #fff | ||||
| 		fill $theme-color | ||||
| 		color $theme-color-foreground | ||||
| 		fill var(--primary) | ||||
| 		color var(--primaryForeground) | ||||
|  | ||||
| 		.octo-arm | ||||
| 			transform-origin 130px 106px | ||||
|   | ||||
| @@ -186,9 +186,8 @@ export default Vue.extend({ | ||||
| 		if (this.game.isStarted && !this.game.isEnded) { | ||||
| 			this.pollingClock = setInterval(() => { | ||||
| 				const crc32 = CRC32.str(this.logs.map(x => x.pos.toString()).join('')); | ||||
| 				this.connection.send({ | ||||
| 					type: 'check', | ||||
| 					crc32 | ||||
| 				this.connection.send('check', { | ||||
| 					crc32: crc32 | ||||
| 				}); | ||||
| 			}, 3000); | ||||
| 		} | ||||
| @@ -224,9 +223,8 @@ export default Vue.extend({ | ||||
| 				sound.play(); | ||||
| 			} | ||||
|  | ||||
| 			this.connection.send({ | ||||
| 				type: 'set', | ||||
| 				pos | ||||
| 			this.connection.send('set', { | ||||
| 				pos: pos | ||||
| 			}); | ||||
|  | ||||
| 			this.checkEnd(); | ||||
| @@ -304,9 +302,7 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
| .xqnhankfuuilcwvhgsopeqncafzsquya | ||||
| 	text-align center | ||||
|  | ||||
| 	> .go-index | ||||
| @@ -319,7 +315,7 @@ root(isDark) | ||||
|  | ||||
| 	> header | ||||
| 		padding 8px | ||||
| 		border-bottom dashed 1px isDark ? #4c5761 : #c4cdd4 | ||||
| 		border-bottom dashed 1px var(--reversiGameHeaderLine) | ||||
|  | ||||
| 		a | ||||
| 			color inherit | ||||
| @@ -386,30 +382,30 @@ root(isDark) | ||||
| 						user-select none | ||||
|  | ||||
| 					&.empty | ||||
| 						border solid 2px isDark ? #51595f : #eee | ||||
| 						border solid 2px var(--reversiGameEmptyCell) | ||||
|  | ||||
| 					&.empty.can | ||||
| 						background isDark ? #51595f : #eee | ||||
| 						background var(--reversiGameEmptyCell) | ||||
|  | ||||
| 					&.empty.myTurn | ||||
| 						border-color isDark ? #6a767f : #ddd | ||||
| 						border-color var(--reversiGameEmptyCellMyTurn) | ||||
|  | ||||
| 						&.can | ||||
| 							background isDark ? #51595f : #eee | ||||
| 							background var(--reversiGameEmptyCellCanPut) | ||||
| 							cursor pointer | ||||
|  | ||||
| 							&:hover | ||||
| 								border-color darken($theme-color, 10%) | ||||
| 								background $theme-color | ||||
| 								border-color var(--primaryDarken10) | ||||
| 								background var(--primary) | ||||
|  | ||||
| 							&:active | ||||
| 								background darken($theme-color, 10%) | ||||
| 								background var(--primaryDarken10) | ||||
|  | ||||
| 					&.prev | ||||
| 						box-shadow 0 0 0 4px rgba($theme-color, 0.7) | ||||
| 						box-shadow 0 0 0 4px var(--primaryAlpha07) | ||||
|  | ||||
| 					&.isEnded | ||||
| 						border-color isDark ? #6a767f : #ddd | ||||
| 						border-color var(--reversiGameEmptyCellMyTurn) | ||||
|  | ||||
| 					&.none | ||||
| 						border-color transparent !important | ||||
| @@ -458,10 +454,4 @@ root(isDark) | ||||
| 			margin 0 8px | ||||
| 			min-width 70px | ||||
|  | ||||
| .xqnhankfuuilcwvhgsopeqncafzsquya[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .xqnhankfuuilcwvhgsopeqncafzsquya:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -9,7 +9,6 @@ | ||||
| import Vue from 'vue'; | ||||
| import XGame from './reversi.game.vue'; | ||||
| import XRoom from './reversi.room.vue'; | ||||
| import { ReversiGameStream } from '../../../../scripts/streaming/games/reversi/reversi-game'; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	components: { | ||||
| @@ -34,12 +33,13 @@ export default Vue.extend({ | ||||
| 	}, | ||||
| 	created() { | ||||
| 		this.g = this.game; | ||||
| 		this.connection = new ReversiGameStream((this as any).os, this.$store.state.i, this.game); | ||||
| 		this.connection = (this as any).os.stream.connectToChannel('gamesReversiGame', { | ||||
| 			gameId: this.game.id | ||||
| 		}); | ||||
| 		this.connection.on('started', this.onStarted); | ||||
| 	}, | ||||
| 	beforeDestroy() { | ||||
| 		this.connection.off('started', this.onStarted); | ||||
| 		this.connection.close(); | ||||
| 		this.connection.dispose(); | ||||
| 	}, | ||||
| 	methods: { | ||||
| 		onStarted(game) { | ||||
|   | ||||
| @@ -59,15 +59,13 @@ export default Vue.extend({ | ||||
| 			myGames: [], | ||||
| 			matching: null, | ||||
| 			invitations: [], | ||||
| 			connection: null, | ||||
| 			connectionId: null | ||||
| 			connection: null | ||||
| 		}; | ||||
| 	}, | ||||
|  | ||||
| 	mounted() { | ||||
| 		if (this.$store.getters.isSignedIn) { | ||||
| 			this.connection = (this as any).os.streams.reversiStream.getConnection(); | ||||
| 			this.connectionId = (this as any).os.streams.reversiStream.use(); | ||||
| 			this.connection = (this as any).os.stream.useSharedConnection('gamesReversi'); | ||||
|  | ||||
| 			this.connection.on('invited', this.onInvited); | ||||
|  | ||||
| @@ -90,8 +88,7 @@ export default Vue.extend({ | ||||
|  | ||||
| 	beforeDestroy() { | ||||
| 		if (this.connection) { | ||||
| 			this.connection.off('invited', this.onInvited); | ||||
| 			(this as any).os.streams.reversiStream.dispose(this.connectionId); | ||||
| 			this.connection.dispose(); | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| @@ -138,9 +135,7 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
| .phgnkghfpyvkrvwiajkiuoxyrdaqpzcx | ||||
| 	> h1 | ||||
| 		margin 0 | ||||
| 		padding 24px | ||||
| @@ -148,7 +143,7 @@ root(isDark) | ||||
| 		text-align center | ||||
| 		font-weight normal | ||||
| 		color #fff | ||||
| 		background linear-gradient(to bottom, isDark ? #45730e : #8bca3e, isDark ? #464300 : #d6cf31) | ||||
| 		background linear-gradient(to bottom, var(--reversiBannerGradientStart), var(--reversiBannerGradientEnd)) | ||||
|  | ||||
| 		& + p | ||||
| 			margin 0 | ||||
| @@ -156,7 +151,7 @@ root(isDark) | ||||
| 			margin-bottom 12px | ||||
| 			text-align center | ||||
| 			font-size 14px | ||||
| 			border-bottom solid 1px isDark ? #535f65 : #d3d9dc | ||||
| 			border-bottom solid 1px var(--faceDivider) | ||||
|  | ||||
| 	> .play | ||||
| 		margin 0 auto | ||||
| @@ -171,14 +166,14 @@ root(isDark) | ||||
| 				padding 16px | ||||
| 				font-size 14px | ||||
| 				text-align left | ||||
| 				background isDark ? #282c37 : #f5f5f5 | ||||
| 				background var(--reversiDescBg) | ||||
| 				border-radius 8px | ||||
|  | ||||
| 	> section | ||||
| 		margin 0 auto | ||||
| 		padding 0 16px 16px 16px | ||||
| 		max-width 500px | ||||
| 		border-top solid 1px isDark ? #535f65 : #d3d9dc | ||||
| 		border-top solid 1px var(--faceDivider) | ||||
|  | ||||
| 		> h2 | ||||
| 			margin 0 | ||||
| @@ -189,9 +184,9 @@ root(isDark) | ||||
| 	.invitation | ||||
| 		margin 8px 0 | ||||
| 		padding 8px | ||||
| 		color isDark ? #fff : #677f84 | ||||
| 		background isDark ? #282c37 : #fff | ||||
| 		box-shadow 0 2px 16px rgba(#000, isDark ? 0.7 : 0.15) | ||||
| 		color var(--text) | ||||
| 		background var(--face) | ||||
| 		box-shadow 0 2px 16px var(--reversiListItemShadow) | ||||
| 		border-radius 6px | ||||
| 		cursor pointer | ||||
|  | ||||
| @@ -200,13 +195,13 @@ root(isDark) | ||||
| 			user-select none | ||||
|  | ||||
| 		&:focus | ||||
| 			border-color $theme-color | ||||
| 			border-color var(--primary) | ||||
|  | ||||
| 		&:hover | ||||
| 			background isDark ? #313543 : #f5f5f5 | ||||
| 			box-shadow 0 0 0 100px inset rgba(0, 0, 0, 0.05) | ||||
|  | ||||
| 		&:active | ||||
| 			background isDark ? #1e222b : #eee | ||||
| 			box-shadow 0 0 0 100px inset rgba(0, 0, 0, 0.1) | ||||
|  | ||||
| 		> .avatar | ||||
| 			width 32px | ||||
| @@ -221,9 +216,9 @@ root(isDark) | ||||
| 		display block | ||||
| 		margin 8px 0 | ||||
| 		padding 8px | ||||
| 		color isDark ? #fff : #677f84 | ||||
| 		background isDark ? #282c37 : #fff | ||||
| 		box-shadow 0 2px 16px rgba(#000, isDark ? 0.7 : 0.15) | ||||
| 		color var(--text) | ||||
| 		background var(--face) | ||||
| 		box-shadow 0 2px 16px var(--reversiListItemShadow) | ||||
| 		border-radius 6px | ||||
| 		cursor pointer | ||||
|  | ||||
| @@ -232,10 +227,10 @@ root(isDark) | ||||
| 			user-select none | ||||
|  | ||||
| 		&:hover | ||||
| 			background isDark ? #313543 : #f5f5f5 | ||||
| 			box-shadow 0 0 0 100px inset rgba(0, 0, 0, 0.05) | ||||
|  | ||||
| 		&:active | ||||
| 			background isDark ? #1e222b : #eee | ||||
| 			box-shadow 0 0 0 100px inset rgba(0, 0, 0, 0.1) | ||||
|  | ||||
| 		> .avatar | ||||
| 			width 32px | ||||
| @@ -246,10 +241,4 @@ root(isDark) | ||||
| 			margin 0 8px | ||||
| 			line-height 32px | ||||
|  | ||||
| .phgnkghfpyvkrvwiajkiuoxyrdaqpzcx[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .phgnkghfpyvkrvwiajkiuoxyrdaqpzcx:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -47,9 +47,9 @@ | ||||
| 			</header> | ||||
|  | ||||
| 			<div> | ||||
| 				<mk-switch v-model="game.settings.isLlotheo" @change="updateSettings" text="%i18n:@is-llotheo%"/> | ||||
| 				<mk-switch v-model="game.settings.loopedBoard" @change="updateSettings" text="%i18n:@looped-map%"/> | ||||
| 				<mk-switch v-model="game.settings.canPutEverywhere" @change="updateSettings" text="%i18n:@can-put-everywhere%"/> | ||||
| 				<ui-switch v-model="game.settings.isLlotheo" @change="updateSettings">%i18n:@is-llotheo%</ui-switch> | ||||
| 				<ui-switch v-model="game.settings.loopedBoard" @change="updateSettings">%i18n:@looped-map%</ui-switch> | ||||
| 				<ui-switch v-model="game.settings.canPutEverywhere" @change="updateSettings">%i18n:@can-put-everywhere%</ui-switch> | ||||
| 			</div> | ||||
| 		</div> | ||||
|  | ||||
| @@ -60,7 +60,7 @@ | ||||
|  | ||||
| 			<div> | ||||
| 				<template v-for="item in form"> | ||||
| 					<mk-switch v-if="item.type == 'switch'" v-model="item.value" :key="item.id" :text="item.label" @change="onChangeForm(item)">{{ item.desc || '' }}</mk-switch> | ||||
| 					<ui-switch v-if="item.type == 'switch'" v-model="item.value" :key="item.id" :text="item.label" @change="onChangeForm(item)">{{ item.desc || '' }}</ui-switch> | ||||
|  | ||||
| 					<div class="card" v-if="item.type == 'radio'" :key="item.id"> | ||||
| 						<header> | ||||
| @@ -149,9 +149,9 @@ export default Vue.extend({ | ||||
| 	}, | ||||
|  | ||||
| 	created() { | ||||
| 		this.connection.on('change-accepts', this.onChangeAccepts); | ||||
| 		this.connection.on('update-settings', this.onUpdateSettings); | ||||
| 		this.connection.on('init-form', this.onInitForm); | ||||
| 		this.connection.on('changeAccepts', this.onChangeAccepts); | ||||
| 		this.connection.on('updateSettings', this.onUpdateSettings); | ||||
| 		this.connection.on('initForm', this.onInitForm); | ||||
| 		this.connection.on('message', this.onMessage); | ||||
|  | ||||
| 		if (this.game.user1Id != this.$store.state.i.id && this.game.settings.form1) this.form = this.game.settings.form1; | ||||
| @@ -159,9 +159,9 @@ export default Vue.extend({ | ||||
| 	}, | ||||
|  | ||||
| 	beforeDestroy() { | ||||
| 		this.connection.off('change-accepts', this.onChangeAccepts); | ||||
| 		this.connection.off('update-settings', this.onUpdateSettings); | ||||
| 		this.connection.off('init-form', this.onInitForm); | ||||
| 		this.connection.off('changeAccepts', this.onChangeAccepts); | ||||
| 		this.connection.off('updateSettings', this.onUpdateSettings); | ||||
| 		this.connection.off('initForm', this.onInitForm); | ||||
| 		this.connection.off('message', this.onMessage); | ||||
| 	}, | ||||
|  | ||||
| @@ -171,15 +171,11 @@ export default Vue.extend({ | ||||
| 		}, | ||||
|  | ||||
| 		accept() { | ||||
| 			this.connection.send({ | ||||
| 				type: 'accept' | ||||
| 			}); | ||||
| 			this.connection.send('accept', {}); | ||||
| 		}, | ||||
|  | ||||
| 		cancel() { | ||||
| 			this.connection.send({ | ||||
| 				type: 'cancel-accept' | ||||
| 			}); | ||||
| 			this.connection.send('cancelAccept', {}); | ||||
| 		}, | ||||
|  | ||||
| 		onChangeAccepts(accepts) { | ||||
| @@ -189,8 +185,7 @@ export default Vue.extend({ | ||||
| 		}, | ||||
|  | ||||
| 		updateSettings() { | ||||
| 			this.connection.send({ | ||||
| 				type: 'update-settings', | ||||
| 			this.connection.send('updateSettings', { | ||||
| 				settings: this.game.settings | ||||
| 			}); | ||||
| 		}, | ||||
| @@ -216,8 +211,7 @@ export default Vue.extend({ | ||||
| 		}, | ||||
|  | ||||
| 		onChangeForm(item) { | ||||
| 			this.connection.send({ | ||||
| 				type: 'update-form', | ||||
| 			this.connection.send('updateForm', { | ||||
| 				id: item.id, | ||||
| 				value: item.value | ||||
| 			}); | ||||
| @@ -252,11 +246,9 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
| .urbixznjwwuukfsckrwzwsqzsxornqij | ||||
| 	text-align center | ||||
| 	background isDark ? #191b22 : #f9f9f9 | ||||
| 	background var(--bg) | ||||
|  | ||||
| 	> header | ||||
| 		padding 8px | ||||
| @@ -273,10 +265,10 @@ root(isDark) | ||||
| 					> select | ||||
| 						width 100% | ||||
| 						padding 12px 14px | ||||
| 						background isDark ? #282C37 : #fff | ||||
| 						border 1px solid isDark ? #6a707d : #dcdfe6 | ||||
| 						background var(--face) | ||||
| 						border 1px solid var(--reversiMapSelectBorder) | ||||
| 						border-radius 4px | ||||
| 						color isDark ? #fff : #606266 | ||||
| 						color var(--text) | ||||
| 						cursor pointer | ||||
| 						transition border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) | ||||
| 						-webkit-appearance none | ||||
| @@ -284,17 +276,18 @@ root(isDark) | ||||
| 						appearance none | ||||
|  | ||||
| 						&:hover | ||||
| 							border-color isDark ? #a7aebd : #c0c4cc | ||||
| 							border-color var(--reversiMapSelectHoverBorder) | ||||
|  | ||||
| 						&:focus | ||||
| 						&:active | ||||
| 							border-color $theme-color | ||||
| 							border-color var(--primary) | ||||
|  | ||||
| 				> div | ||||
| 					> .random | ||||
| 						padding 32px 0 | ||||
| 						font-size 64px | ||||
| 						color isDark ? #4e5961 : #d8d8d8 | ||||
| 						color var(--text) | ||||
| 						opacity 0.7 | ||||
|  | ||||
| 					> .board | ||||
| 						display grid | ||||
| @@ -302,11 +295,11 @@ root(isDark) | ||||
| 						width 300px | ||||
| 						height 300px | ||||
| 						margin 0 auto | ||||
| 						color isDark ? #fff : #444 | ||||
| 						color var(--text) | ||||
|  | ||||
| 						> div | ||||
| 							background transparent | ||||
| 							border solid 2px isDark ? #6a767f : #ddd | ||||
| 							border solid 2px var(--faceDivider) | ||||
| 							border-radius 6px | ||||
| 							overflow hidden | ||||
| 							cursor pointer | ||||
| @@ -331,32 +324,26 @@ root(isDark) | ||||
| 		.card | ||||
| 			max-width 400px | ||||
| 			border-radius 4px | ||||
| 			background isDark ? #282C37 : #fff | ||||
| 			color isDark ? #fff : #303133 | ||||
| 			box-shadow 0 2px 12px 0 rgba(#000, isDark ? 0.7 : 0.1) | ||||
| 			background var(--face) | ||||
| 			color var(--text) | ||||
| 			box-shadow 0 2px 12px 0 var(--reversiRoomFormShadow) | ||||
|  | ||||
| 			> header | ||||
| 				padding 18px 20px | ||||
| 				border-bottom 1px solid isDark ? #1c2023 : #ebeef5 | ||||
| 				border-bottom 1px solid var(--faceDivider) | ||||
|  | ||||
| 			> div | ||||
| 				padding 20px | ||||
| 				color isDark ? #fff : #606266 | ||||
| 				color var(--text) | ||||
|  | ||||
| 	> footer | ||||
| 		position sticky | ||||
| 		bottom 0 | ||||
| 		padding 16px | ||||
| 		background rgba(isDark ? #191b22 : #fff, 0.9) | ||||
| 		border-top solid 1px isDark ? #606266 : #c4cdd4 | ||||
| 		background var(--reversiRoomFooterBg) | ||||
| 		border-top solid 1px var(--faceDivider) | ||||
|  | ||||
| 		> .status | ||||
| 			margin 0 0 16px 0 | ||||
|  | ||||
| .urbixznjwwuukfsckrwzwsqzsxornqij[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .urbixznjwwuukfsckrwzwsqzsxornqij:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -47,7 +47,6 @@ export default Vue.extend({ | ||||
| 			game: null, | ||||
| 			matching: null, | ||||
| 			connection: null, | ||||
| 			connectionId: null, | ||||
| 			pingClock: null | ||||
| 		}; | ||||
| 	}, | ||||
| @@ -66,8 +65,7 @@ export default Vue.extend({ | ||||
| 		this.fetch(); | ||||
|  | ||||
| 		if (this.$store.getters.isSignedIn) { | ||||
| 			this.connection = (this as any).os.streams.reversiStream.getConnection(); | ||||
| 			this.connectionId = (this as any).os.streams.reversiStream.use(); | ||||
| 			this.connection = (this as any).os.stream.useSharedConnection('gamesReversi'); | ||||
|  | ||||
| 			this.connection.on('matched', this.onMatched); | ||||
|  | ||||
| @@ -84,9 +82,7 @@ export default Vue.extend({ | ||||
|  | ||||
| 	beforeDestroy() { | ||||
| 		if (this.connection) { | ||||
| 			this.connection.off('matched', this.onMatched); | ||||
| 			(this as any).os.streams.reversiStream.dispose(this.connectionId); | ||||
|  | ||||
| 			this.connection.dispose(); | ||||
| 			clearInterval(this.pingClock); | ||||
| 		} | ||||
| 	}, | ||||
| @@ -156,11 +152,9 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
| 	color isDark ? #fff : #677f84 | ||||
| 	background isDark ? #191b22 : #fff | ||||
| .vchtoekanapleubgzioubdtmlkribzfd | ||||
| 	color var(--text) | ||||
| 	background var(--bg) | ||||
|  | ||||
| 	> .matching | ||||
| 		> h1 | ||||
| @@ -177,10 +171,4 @@ root(isDark) | ||||
| 			text-align center | ||||
| 			border-top dashed 1px #c4cdd4 | ||||
|  | ||||
| .vchtoekanapleubgzioubdtmlkribzfd[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .vchtoekanapleubgzioubdtmlkribzfd:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -26,7 +26,7 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| root(isDark) | ||||
| .mk-google | ||||
| 	display flex | ||||
| 	margin 8px 0 | ||||
|  | ||||
| @@ -37,31 +37,25 @@ root(isDark) | ||||
| 		height 40px | ||||
| 		font-family sans-serif | ||||
| 		font-size 16px | ||||
| 		color isDark ? #dee4e8 : #55595c | ||||
| 		background isDark ? #191b22 : #fff | ||||
| 		border solid 1px isDark ? #495156 : #dadada | ||||
| 		color var(--googleSearchFg) | ||||
| 		background var(--googleSearchBg) | ||||
| 		border solid 1px var(--googleSearchBorder) | ||||
| 		border-radius 4px 0 0 4px | ||||
|  | ||||
| 		&:hover | ||||
| 			border-color isDark ? #777c86 : #b0b0b0 | ||||
| 			border-color var(--googleSearchHoverBorder) | ||||
|  | ||||
| 	> button | ||||
| 		flex-shrink 0 | ||||
| 		padding 0 16px | ||||
| 		border solid 1px isDark ? #495156 : #dadada | ||||
| 		border solid 1px var(--googleSearchBorder) | ||||
| 		border-left none | ||||
| 		border-radius 0 4px 4px 0 | ||||
|  | ||||
| 		&:hover | ||||
| 			background-color isDark ? #2e3440 : #eee | ||||
| 			background-color var(--googleSearchHoverButton) | ||||
|  | ||||
| 		&:active | ||||
| 			box-shadow 0 2px 4px rgba(#000, 0.15) inset | ||||
|  | ||||
| .mk-google[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .mk-google:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -1,5 +1,7 @@ | ||||
| import Vue from 'vue'; | ||||
|  | ||||
| import theme from './theme.vue'; | ||||
| import instance from './instance.vue'; | ||||
| import cwButton from './cw-button.vue'; | ||||
| import tagCloud from './tag-cloud.vue'; | ||||
| import trends from './trends.vue'; | ||||
| @@ -29,7 +31,6 @@ import messagingRoom from './messaging-room.vue'; | ||||
| import urlPreview from './url-preview.vue'; | ||||
| import twitterSetting from './twitter-setting.vue'; | ||||
| import fileTypeIcon from './file-type-icon.vue'; | ||||
| import Switch from './switch.vue'; | ||||
| import Reversi from './games/reversi/reversi.vue'; | ||||
| import welcomeTimeline from './welcome-timeline.vue'; | ||||
| import uiInput from './ui/input.vue'; | ||||
| @@ -43,6 +44,8 @@ import uiSelect from './ui/select.vue'; | ||||
| import formButton from './ui/form/button.vue'; | ||||
| import formRadio from './ui/form/radio.vue'; | ||||
|  | ||||
| Vue.component('mk-theme', theme); | ||||
| Vue.component('mk-instance', instance); | ||||
| Vue.component('mk-cw-button', cwButton); | ||||
| Vue.component('mk-tag-cloud', tagCloud); | ||||
| Vue.component('mk-trends', trends); | ||||
| @@ -72,7 +75,6 @@ Vue.component('mk-messaging-room', messagingRoom); | ||||
| Vue.component('mk-url-preview', urlPreview); | ||||
| Vue.component('mk-twitter-setting', twitterSetting); | ||||
| Vue.component('mk-file-type-icon', fileTypeIcon); | ||||
| Vue.component('mk-switch', Switch); | ||||
| Vue.component('mk-reversi', Reversi); | ||||
| Vue.component('mk-welcome-timeline', welcomeTimeline); | ||||
| Vue.component('ui-input', uiInput); | ||||
|   | ||||
							
								
								
									
										51
									
								
								src/client/app/common/views/components/instance.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/client/app/common/views/components/instance.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| <template> | ||||
| <div class="nhasjydimbopojusarffqjyktglcuxjy" v-if="meta"> | ||||
| 	<div class="banner" :style="{ backgroundImage: meta.bannerUrl ? `url(${meta.bannerUrl})` : null }"></div> | ||||
|  | ||||
| 	<h1>{{ meta.name }}</h1> | ||||
| 	<p v-html="meta.description || '%i18n:common.about%'"></p> | ||||
| 	<router-link to="/">%i18n:@start%</router-link> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	data() { | ||||
| 		return { | ||||
| 			meta: null | ||||
| 		} | ||||
| 	}, | ||||
| 	created() { | ||||
| 		(this as any).os.getMeta().then(meta => { | ||||
| 			this.meta = meta; | ||||
| 		}); | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| .nhasjydimbopojusarffqjyktglcuxjy | ||||
| 	color var(--text) | ||||
| 	background var(--face) | ||||
| 	text-align center | ||||
|  | ||||
| 	> .banner | ||||
| 		height 100px | ||||
| 		background-position center | ||||
| 		background-size cover | ||||
|  | ||||
| 	> h1 | ||||
| 		margin 16px | ||||
| 		font-size 16px | ||||
|  | ||||
| 	> p | ||||
| 		margin 16px | ||||
| 		font-size 14px | ||||
|  | ||||
| 	> a | ||||
| 		display block | ||||
| 		padding-bottom 16px | ||||
|  | ||||
| </style> | ||||
| @@ -43,7 +43,7 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| root(isDark) | ||||
| .mk-media-banner | ||||
| 	width 100% | ||||
| 	border-radius 4px | ||||
| 	margin-top 4px | ||||
| @@ -71,7 +71,7 @@ root(isDark) | ||||
| 			font-size 1.6em | ||||
|  | ||||
| 	> .download | ||||
| 		background isDark ? #21242d : #f7f7f7 | ||||
| 		background var(--noteAttachedFile) | ||||
|  | ||||
| 	> .sensitive | ||||
| 		background #111 | ||||
| @@ -82,9 +82,4 @@ root(isDark) | ||||
| 			display block | ||||
| 			width 100% | ||||
|  | ||||
| .mk-media-banner[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .mk-media-banner:not([data-darkmode]) | ||||
| 	root(false) | ||||
| </style> | ||||
|   | ||||
| @@ -117,10 +117,8 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
| 	$bg-color = isDark ? #2c303c : #fff | ||||
| .onchrpzrvnoruiaenfcqvccjfuupzzwv | ||||
| 	$bg-color = var(--popupBg) | ||||
| 	$border-color = rgba(27, 31, 35, 0.15) | ||||
|  | ||||
| 	position initial | ||||
| @@ -132,7 +130,7 @@ root(isDark) | ||||
| 		z-index 10000 | ||||
| 		width 100% | ||||
| 		height 100% | ||||
| 		background rgba(#000, isDark ? 0.5 : 0.1) | ||||
| 		background var(--modalBackdrop) | ||||
| 		opacity 0 | ||||
|  | ||||
| 	> .popover | ||||
| @@ -179,26 +177,20 @@ root(isDark) | ||||
| 			display block | ||||
| 			padding 8px 16px | ||||
| 			width 100% | ||||
| 			color isDark ? #d6dce2 : #111 | ||||
| 			color var(--popupFg) | ||||
|  | ||||
| 			&:hover | ||||
| 				color $theme-color-foreground | ||||
| 				background $theme-color | ||||
| 				color var(--primaryForeground) | ||||
| 				background var(--primary) | ||||
| 				text-decoration none | ||||
|  | ||||
| 			&:active | ||||
| 				color $theme-color-foreground | ||||
| 				background darken($theme-color, 10%) | ||||
| 				color var(--primaryForeground) | ||||
| 				background var(--primaryDarken10) | ||||
|  | ||||
| 		> div | ||||
| 			margin 8px 0 | ||||
| 			height 1px | ||||
| 			background isDark ? #1c2023 : #eee | ||||
|  | ||||
| .onchrpzrvnoruiaenfcqvccjfuupzzwv[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .onchrpzrvnoruiaenfcqvccjfuupzzwv:not([data-darkmode]) | ||||
| 	root(false) | ||||
| 			background var(--faceDivider) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -195,9 +195,7 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
| .mk-messaging-form | ||||
| 	> textarea | ||||
| 		cursor auto | ||||
| 		display block | ||||
| @@ -209,10 +207,10 @@ root(isDark) | ||||
| 		padding 8px | ||||
| 		resize none | ||||
| 		font-size 1em | ||||
| 		color isDark ? #fff : #000 | ||||
| 		color var(--inputText) | ||||
| 		outline none | ||||
| 		border none | ||||
| 		border-top solid 1px isDark ? #4b5056 : #eee | ||||
| 		border-top solid 1px var(--faceDivider) | ||||
| 		border-radius 0 | ||||
| 		box-shadow none | ||||
| 		background transparent | ||||
| @@ -234,10 +232,10 @@ root(isDark) | ||||
| 		transition color 0.1s ease | ||||
|  | ||||
| 		&:hover | ||||
| 			color $theme-color | ||||
| 			color var(--primary) | ||||
|  | ||||
| 		&:active | ||||
| 			color darken($theme-color, 10%) | ||||
| 			color var(--primaryDarken10) | ||||
| 			transition color 0s ease | ||||
|  | ||||
| 	.files | ||||
| @@ -293,19 +291,13 @@ root(isDark) | ||||
| 		transition color 0.1s ease | ||||
|  | ||||
| 		&:hover | ||||
| 			color $theme-color | ||||
| 			color var(--primary) | ||||
|  | ||||
| 		&:active | ||||
| 			color darken($theme-color, 10%) | ||||
| 			color var(--primaryDarken10) | ||||
| 			transition color 0s ease | ||||
|  | ||||
| 	input[type=file] | ||||
| 		display none | ||||
|  | ||||
| .mk-messaging-form[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .mk-messaging-form:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -59,10 +59,8 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
| 	$me-balloon-color = $theme-color | ||||
| .message | ||||
| 	$me-balloon-color = var(--primary) | ||||
|  | ||||
| 	padding 10px 12px 10px 12px | ||||
| 	background-color transparent | ||||
| @@ -179,7 +177,7 @@ root(isDark) | ||||
| 			display block | ||||
| 			margin 2px 0 0 0 | ||||
| 			font-size 10px | ||||
| 			color isDark ? rgba(#fff, 0.4) : rgba(#000, 0.4) | ||||
| 			color var(--messagingRoomMessageInfo) | ||||
|  | ||||
| 			> [data-fa] | ||||
| 				margin-left 4px | ||||
| @@ -192,7 +190,7 @@ root(isDark) | ||||
| 			padding-left 66px | ||||
|  | ||||
| 			> .balloon | ||||
| 				$color = isDark ? #2d3338 : #eee | ||||
| 				$color = var(--messagingRoomMessageBg) | ||||
| 				float left | ||||
| 				background $color | ||||
|  | ||||
| @@ -208,8 +206,7 @@ root(isDark) | ||||
|  | ||||
| 				> .content | ||||
| 					> .text | ||||
| 						if isDark | ||||
| 							color #fff | ||||
| 							color var(--messagingRoomMessageFg) | ||||
|  | ||||
| 			> footer | ||||
| 				text-align left | ||||
| @@ -250,18 +247,9 @@ root(isDark) | ||||
|  | ||||
| 				> .read | ||||
| 					user-select none | ||||
| 					margin 0 4px 0 0 | ||||
| 					color isDark ? rgba(#fff, 0.5) : rgba(#000, 0.5) | ||||
| 					font-size 11px | ||||
|  | ||||
| 	&[data-is-deleted] | ||||
| 		> .balloon | ||||
| 			opacity 0.5 | ||||
|  | ||||
| .message[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .message:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -30,7 +30,6 @@ | ||||
|  | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import { MessagingStream } from '../../scripts/streaming/messaging'; | ||||
| import XMessage from './messaging-room.message.vue'; | ||||
| import XForm from './messaging-room.form.vue'; | ||||
| import { url } from '../../../config'; | ||||
| @@ -72,7 +71,7 @@ export default Vue.extend({ | ||||
| 	}, | ||||
|  | ||||
| 	mounted() { | ||||
| 		this.connection = new MessagingStream((this as any).os, this.$store.state.i, this.user.id); | ||||
| 		this.connection =((this as any).os.stream.connectToChannel('messaging', { otherparty: this.user.id }); | ||||
|  | ||||
| 		this.connection.on('message', this.onMessage); | ||||
| 		this.connection.on('read', this.onRead); | ||||
| @@ -92,9 +91,7 @@ export default Vue.extend({ | ||||
| 	}, | ||||
|  | ||||
| 	beforeDestroy() { | ||||
| 		this.connection.off('message', this.onMessage); | ||||
| 		this.connection.off('read', this.onRead); | ||||
| 		this.connection.close(); | ||||
| 		this.connection.dispose(); | ||||
|  | ||||
| 		if (this.isNaked) { | ||||
| 			window.removeEventListener('scroll', this.onScroll); | ||||
| @@ -177,8 +174,7 @@ export default Vue.extend({ | ||||
|  | ||||
| 			this.messages.push(message); | ||||
| 			if (message.userId != this.$store.state.i.id && !document.hidden) { | ||||
| 				this.connection.send({ | ||||
| 					type: 'read', | ||||
| 				this.connection.send('read', { | ||||
| 					id: message.id | ||||
| 				}); | ||||
| 			} | ||||
| @@ -250,8 +246,7 @@ export default Vue.extend({ | ||||
| 			if (document.hidden) return; | ||||
| 			this.messages.forEach(message => { | ||||
| 				if (message.userId !== this.$store.state.i.id && !message.isRead) { | ||||
| 					this.connection.send({ | ||||
| 						type: 'read', | ||||
| 					this.connection.send('read', { | ||||
| 						id: message.id | ||||
| 					}); | ||||
| 				} | ||||
| @@ -262,14 +257,12 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
| .mk-messaging-room | ||||
| 	display flex | ||||
| 	flex 1 | ||||
| 	flex-direction column | ||||
| 	height 100% | ||||
| 	background isDark ? #191b22 : #fff | ||||
| 	background var(--messagingRoomBg) | ||||
|  | ||||
| 	> .body | ||||
| 		width 100% | ||||
| @@ -277,24 +270,15 @@ root(isDark) | ||||
| 		margin 0 auto | ||||
| 		flex 1 | ||||
|  | ||||
| 		> .init | ||||
| 			width 100% | ||||
| 			margin 0 | ||||
| 			padding 16px 8px 8px 8px | ||||
| 			text-align center | ||||
| 			font-size 0.8em | ||||
| 			color rgba(isDark ? #fff : #000, 0.4) | ||||
|  | ||||
| 			[data-fa] | ||||
| 				margin-right 4px | ||||
|  | ||||
| 		> .init, | ||||
| 		> .empty | ||||
| 			width 100% | ||||
| 			margin 0 | ||||
| 			padding 16px 8px 8px 8px | ||||
| 			text-align center | ||||
| 			font-size 0.8em | ||||
| 			color rgba(isDark ? #fff : #000, 0.4) | ||||
| 			color var(--messagingRoomInfo) | ||||
| 			opacity 0.5 | ||||
|  | ||||
| 			[data-fa] | ||||
| 				margin-right 4px | ||||
| @@ -305,7 +289,8 @@ root(isDark) | ||||
| 			padding 16px | ||||
| 			text-align center | ||||
| 			font-size 0.8em | ||||
| 			color rgba(isDark ? #fff : #000, 0.4) | ||||
| 			color var(--messagingRoomInfo) | ||||
| 			opacity 0.5 | ||||
|  | ||||
| 			[data-fa] | ||||
| 				margin-right 4px | ||||
| @@ -349,7 +334,7 @@ root(isDark) | ||||
| 				left 0 | ||||
| 				right 0 | ||||
| 				margin 0 auto | ||||
| 				background rgba(isDark ? #fff : #000, 0.1) | ||||
| 				background var(--messagingRoomDateDividerLine) | ||||
|  | ||||
| 			> span | ||||
| 				display inline-block | ||||
| @@ -357,8 +342,8 @@ root(isDark) | ||||
| 				padding 0 16px | ||||
| 				//font-weight bold | ||||
| 				line-height 32px | ||||
| 				color rgba(isDark ? #fff : #000, 0.3) | ||||
| 				background isDark ? #191b22 : #fff | ||||
| 				color var(--messagingRoomDateDividerText) | ||||
| 				background var(--messagingRoomBg) | ||||
|  | ||||
| 	> footer | ||||
| 		position -webkit-sticky | ||||
| @@ -369,7 +354,7 @@ root(isDark) | ||||
| 		max-width 600px | ||||
| 		margin 0 auto | ||||
| 		padding 0 | ||||
| 		background rgba(isDark ? #282c37 : #fff, 0.95) | ||||
| 		//background rgba(var(--face), 0.95) | ||||
| 		background-clip content-box | ||||
|  | ||||
| 		> .new-message | ||||
| @@ -386,15 +371,15 @@ root(isDark) | ||||
| 				cursor pointer | ||||
| 				line-height 32px | ||||
| 				font-size 12px | ||||
| 				color $theme-color-foreground | ||||
| 				background $theme-color | ||||
| 				color var(--primaryForeground) | ||||
| 				background var(--primary) | ||||
| 				border-radius 16px | ||||
|  | ||||
| 				&:hover | ||||
| 					background lighten($theme-color, 10%) | ||||
| 					background var(--primaryLighten10) | ||||
|  | ||||
| 				&:active | ||||
| 					background darken($theme-color, 10%) | ||||
| 					background var(--primaryDarken10) | ||||
|  | ||||
| 				> [data-fa] | ||||
| 					position absolute | ||||
| @@ -410,10 +395,4 @@ root(isDark) | ||||
| 	transition opacity 0.5s | ||||
| 	opacity 0 | ||||
|  | ||||
| .mk-messaging-room[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .mk-messaging-room:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -71,13 +71,11 @@ export default Vue.extend({ | ||||
| 			messages: [], | ||||
| 			q: null, | ||||
| 			result: [], | ||||
| 			connection: null, | ||||
| 			connectionId: null | ||||
| 			connection: null | ||||
| 		}; | ||||
| 	}, | ||||
| 	mounted() { | ||||
| 		this.connection = (this as any).os.streams.messagingIndexStream.getConnection(); | ||||
| 		this.connectionId = (this as any).os.streams.messagingIndexStream.use(); | ||||
| 		this.connection = (this as any).os.stream.useSharedConnection('messagingIndex'); | ||||
|  | ||||
| 		this.connection.on('message', this.onMessage); | ||||
| 		this.connection.on('read', this.onRead); | ||||
| @@ -88,9 +86,7 @@ export default Vue.extend({ | ||||
| 		}); | ||||
| 	}, | ||||
| 	beforeDestroy() { | ||||
| 		this.connection.off('message', this.onMessage); | ||||
| 		this.connection.off('read', this.onRead); | ||||
| 		(this as any).os.streams.messagingIndexStream.dispose(this.connectionId); | ||||
| 		this.connection.dispose(); | ||||
| 	}, | ||||
| 	methods: { | ||||
| 		getAcct, | ||||
| @@ -167,9 +163,7 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
| .mk-messaging | ||||
|  | ||||
| 	&[data-compact] | ||||
| 		font-size 0.8em | ||||
| @@ -204,12 +198,10 @@ root(isDark) | ||||
| 		left 0 | ||||
| 		z-index 1 | ||||
| 		width 100% | ||||
| 		background #fff | ||||
| 		box-shadow 0 0px 2px rgba(#000, 0.2) | ||||
|  | ||||
| 		> .form | ||||
| 			padding 8px | ||||
| 			background isDark ? #282c37 : #f7f7f7 | ||||
| 			background rgba(0, 0, 0, 0.02) | ||||
|  | ||||
| 			> label | ||||
| 				display block | ||||
| @@ -229,32 +221,22 @@ root(isDark) | ||||
| 					bottom 0 | ||||
| 					left 0 | ||||
| 					width 1em | ||||
| 					line-height 56px | ||||
| 					line-height 48px | ||||
| 					margin auto | ||||
| 					color #555 | ||||
|  | ||||
| 			> input | ||||
| 				margin 0 | ||||
| 				padding 0 0 0 32px | ||||
| 				padding 0 0 0 42px | ||||
| 				width 100% | ||||
| 				font-size 1em | ||||
| 				line-height 38px | ||||
| 				color #000 | ||||
| 				line-height 48px | ||||
| 				color var(--faceText) | ||||
| 				outline none | ||||
| 				background isDark ? #191b22 : #fff | ||||
| 				border solid 1px isDark ? #495156 : #eee | ||||
| 				background transparent | ||||
| 				border none | ||||
| 				border-radius 5px | ||||
| 				box-shadow none | ||||
| 				transition color 0.5s ease, border 0.5s ease | ||||
|  | ||||
| 				&:hover | ||||
| 					border solid 1px isDark ? #b0b0b0 : #ddd | ||||
| 					transition border 0.2s ease | ||||
|  | ||||
| 				&:focus | ||||
| 					color darken($theme-color, 20%) | ||||
| 					border solid 1px $theme-color | ||||
| 					transition color 0, border 0 | ||||
|  | ||||
| 		> .result | ||||
| 			display block | ||||
| @@ -287,7 +269,7 @@ root(isDark) | ||||
| 					&:hover | ||||
| 					&:focus | ||||
| 						color #fff | ||||
| 						background $theme-color | ||||
| 						background var(--primary) | ||||
|  | ||||
| 						.name | ||||
| 							color #fff | ||||
| @@ -297,7 +279,7 @@ root(isDark) | ||||
|  | ||||
| 					&:active | ||||
| 						color #fff | ||||
| 						background darken($theme-color, 10%) | ||||
| 						background var(--primaryDarken10) | ||||
|  | ||||
| 						.name | ||||
| 							color #fff | ||||
| @@ -329,21 +311,21 @@ root(isDark) | ||||
| 		> a | ||||
| 			display block | ||||
| 			text-decoration none | ||||
| 			background isDark ? #282c37 : #fff | ||||
| 			border-bottom solid 1px isDark ? #1c2023 : #eee | ||||
| 			background var(--face) | ||||
| 			border-bottom solid 1px var(--faceDivider) | ||||
|  | ||||
| 			* | ||||
| 				pointer-events none | ||||
| 				user-select none | ||||
|  | ||||
| 			&:hover | ||||
| 				background isDark ? #1e2129 : #fafafa | ||||
| 				box-shadow 0 0 0 100px inset rgba(0, 0, 0, 0.05) | ||||
|  | ||||
| 				> .avatar | ||||
| 				.avatar | ||||
| 					filter saturate(200%) | ||||
|  | ||||
| 			&:active | ||||
| 				background isDark ? #14161b : #eee | ||||
| 				box-shadow 0 0 0 100px inset rgba(0, 0, 0, 0.1) | ||||
|  | ||||
| 			&[data-is-read] | ||||
| 			&[data-is-me] | ||||
| @@ -383,17 +365,17 @@ root(isDark) | ||||
| 						overflow hidden | ||||
| 						text-overflow ellipsis | ||||
| 						font-size 1em | ||||
| 						color isDark ? #fff : rgba(#000, 0.9) | ||||
| 						color var(--noteHeaderName) | ||||
| 						font-weight bold | ||||
| 						transition all 0.1s ease | ||||
|  | ||||
| 					> .username | ||||
| 						margin 0 8px | ||||
| 						color isDark ? #606984 : rgba(#000, 0.5) | ||||
| 						color var(--noteHeaderAcct) | ||||
|  | ||||
| 					> .mk-time | ||||
| 						margin 0 0 0 auto | ||||
| 						color isDark ? #606984 : rgba(#000, 0.5) | ||||
| 						color var(--noteHeaderInfo) | ||||
| 						font-size 80% | ||||
|  | ||||
| 				> .avatar | ||||
| @@ -413,10 +395,10 @@ root(isDark) | ||||
| 						overflow hidden | ||||
| 						overflow-wrap break-word | ||||
| 						font-size 1.1em | ||||
| 						color isDark ? #fff : rgba(#000, 0.8) | ||||
| 						color var(--faceText) | ||||
|  | ||||
| 						.me | ||||
| 							color isDark ? rgba(#fff, 0.7) : rgba(#000, 0.4) | ||||
| 							opacity 0.7 | ||||
|  | ||||
| 					> .image | ||||
| 						display block | ||||
| @@ -461,10 +443,4 @@ root(isDark) | ||||
| 					> .avatar | ||||
| 						margin 0 12px 0 0 | ||||
|  | ||||
| .mk-messaging[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .mk-messaging:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -95,7 +95,8 @@ export default Vue.component('misskey-flavored-markdown', { | ||||
| 					return [createElement(MkUrl, { | ||||
| 						props: { | ||||
| 							url: token.content, | ||||
| 							target: '_blank' | ||||
| 							target: '_blank', | ||||
| 							style: 'color:var(--mfmLink);' | ||||
| 						} | ||||
| 					})]; | ||||
| 				} | ||||
| @@ -106,7 +107,8 @@ export default Vue.component('misskey-flavored-markdown', { | ||||
| 							class: 'link', | ||||
| 							href: token.url, | ||||
| 							target: '_blank', | ||||
| 							title: token.url | ||||
| 							title: token.url, | ||||
| 							style: 'color:var(--mfmLink);' | ||||
| 						} | ||||
| 					}, token.title)]; | ||||
| 				} | ||||
| @@ -116,7 +118,8 @@ export default Vue.component('misskey-flavored-markdown', { | ||||
| 						attrs: { | ||||
| 							href: `${url}/@${getAcct(token)}`, | ||||
| 							target: '_blank', | ||||
| 							dataIsMe: (this as any).i && getAcct((this as any).i) == getAcct(token) | ||||
| 							dataIsMe: (this as any).i && getAcct((this as any).i) == getAcct(token), | ||||
| 							style: 'color:var(--mfmMention);' | ||||
| 						}, | ||||
| 						directives: [{ | ||||
| 							name: 'user-preview', | ||||
| @@ -129,7 +132,8 @@ export default Vue.component('misskey-flavored-markdown', { | ||||
| 					return [createElement('a', { | ||||
| 						attrs: { | ||||
| 							href: `${url}/tags/${encodeURIComponent(token.hashtag)}`, | ||||
| 							target: '_blank' | ||||
| 							target: '_blank', | ||||
| 							style: 'color:var(--mfmHashtag);' | ||||
| 						} | ||||
| 					}, token.content)]; | ||||
| 				} | ||||
|   | ||||
| @@ -2,6 +2,8 @@ | ||||
| <span class="mk-nav"> | ||||
| 	<a :href="aboutUrl">%i18n:@about%</a> | ||||
| 	<i>・</i> | ||||
| 	<a href="/stats">%i18n:@stats%</a> | ||||
| 	<i>・</i> | ||||
| 	<a :href="repositoryUrl">%i18n:@repository%</a> | ||||
| 	<i>・</i> | ||||
| 	<a :href="feedbackUrl" target="_blank">%i18n:@feedback%</a> | ||||
|   | ||||
| @@ -42,9 +42,7 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
| .bvonvjxbwzaiskogyhbwgyxvcgserpmu | ||||
| 	display flex | ||||
| 	align-items baseline | ||||
| 	white-space nowrap | ||||
| @@ -61,7 +59,7 @@ root(isDark) | ||||
| 		margin 0 .5em 0 0 | ||||
| 		padding 0 | ||||
| 		overflow hidden | ||||
| 		color isDark ? #fff : #627079 | ||||
| 		color var(--noteHeaderName) | ||||
| 		font-size 1em | ||||
| 		font-weight bold | ||||
| 		text-decoration none | ||||
| @@ -82,19 +80,19 @@ root(isDark) | ||||
| 		margin 0 .5em 0 0 | ||||
| 		padding 1px 6px | ||||
| 		font-size 80% | ||||
| 		color isDark ? #758188 : #aaa | ||||
| 		border solid 1px isDark ? #57616f : #ddd | ||||
| 		color var(--noteHeaderBadgeFg) | ||||
| 		background var(--noteHeaderBadgeBg) | ||||
| 		border-radius 3px | ||||
|  | ||||
| 		&.is-admin | ||||
| 			border-color isDark ? #d42c41 : #f56a7b | ||||
| 			color isDark ? #d42c41 : #f56a7b | ||||
| 			background var(--noteHeaderAdminBg) | ||||
| 			color var(--noteHeaderAdminFg) | ||||
|  | ||||
| 	> .username | ||||
| 		margin 0 .5em 0 0 | ||||
| 		overflow hidden | ||||
| 		text-overflow ellipsis | ||||
| 		color isDark ? #606984 : #ccc | ||||
| 		color var(--noteHeaderAcct) | ||||
| 		flex-shrink 2147483647 | ||||
|  | ||||
| 	> .info | ||||
| @@ -102,7 +100,7 @@ root(isDark) | ||||
| 		font-size 0.9em | ||||
|  | ||||
| 		> * | ||||
| 			color isDark ? #606984 : #c0c0c0 | ||||
| 			color var(--noteHeaderInfo) | ||||
|  | ||||
| 		> .mobile | ||||
| 			margin-right 8px | ||||
| @@ -110,15 +108,9 @@ root(isDark) | ||||
| 		> .app | ||||
| 			margin-right 8px | ||||
| 			padding-right 8px | ||||
| 			border-right solid 1px isDark ? #1c2023 : #eaeaea | ||||
| 			border-right solid 1px var(--faceDivider) | ||||
|  | ||||
| 		> .visibility | ||||
| 			margin-left 8px | ||||
|  | ||||
| .bvonvjxbwzaiskogyhbwgyxvcgserpmu[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .bvonvjxbwzaiskogyhbwgyxvcgserpmu:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -28,12 +28,20 @@ export default Vue.extend({ | ||||
| 			}]; | ||||
|  | ||||
| 			if (this.note.userId == this.$store.state.i.id) { | ||||
| 				if ((this.$store.state.i.pinnedNoteIds || []).includes(this.note.id)) { | ||||
| 					items.push({ | ||||
| 						icon: '%fa:thumbtack%', | ||||
| 						text: '%i18n:@unpin%', | ||||
| 						action: this.unpin | ||||
| 					}); | ||||
| 				} else { | ||||
| 					items.push({ | ||||
| 						icon: '%fa:thumbtack%', | ||||
| 						text: '%i18n:@pin%', | ||||
| 						action: this.pin | ||||
| 					}); | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			if (this.note.userId == this.$store.state.i.id || this.$store.state.i.isAdmin) { | ||||
| 				items.push({ | ||||
| @@ -56,6 +64,7 @@ export default Vue.extend({ | ||||
| 			return items; | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	methods: { | ||||
| 		detail() { | ||||
| 			this.$router.push(`/notes/${ this.note.id }`); | ||||
| @@ -73,6 +82,14 @@ export default Vue.extend({ | ||||
| 			}); | ||||
| 		}, | ||||
|  | ||||
| 		unpin() { | ||||
| 			(this as any).api('i/unpin', { | ||||
| 				noteId: this.note.id | ||||
| 			}).then(() => { | ||||
| 				this.destroyDom(); | ||||
| 			}); | ||||
| 		}, | ||||
|  | ||||
| 		del() { | ||||
| 			if (!window.confirm('%i18n:@delete-confirm%')) return; | ||||
| 			(this as any).api('notes/delete', { | ||||
|   | ||||
| @@ -68,9 +68,7 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
| .mk-poll-editor | ||||
| 	padding 8px | ||||
|  | ||||
| 	> .caution | ||||
| @@ -103,49 +101,43 @@ root(isDark) | ||||
| 				padding 6px 8px | ||||
| 				width 300px | ||||
| 				font-size 14px | ||||
| 				color isDark ? #fff : #000 | ||||
| 				background isDark ? #191b22 : #fff | ||||
| 				border solid 1px rgba($theme-color, 0.1) | ||||
| 				color var(--inputText) | ||||
| 				background var(--pollEditorInputBg) | ||||
| 				border solid 1px var(--primaryAlpha01) | ||||
| 				border-radius 4px | ||||
|  | ||||
| 				&:hover | ||||
| 					border-color rgba($theme-color, 0.2) | ||||
| 					border-color var(--primaryAlpha02) | ||||
|  | ||||
| 				&:focus | ||||
| 					border-color rgba($theme-color, 0.5) | ||||
| 					border-color var(--primaryAlpha05) | ||||
|  | ||||
| 			> button | ||||
| 				padding 4px 8px | ||||
| 				color rgba($theme-color, 0.4) | ||||
| 				color var(--primaryAlpha04) | ||||
|  | ||||
| 				&:hover | ||||
| 					color rgba($theme-color, 0.6) | ||||
| 					color var(--primaryAlpha06) | ||||
|  | ||||
| 				&:active | ||||
| 					color darken($theme-color, 30%) | ||||
| 					color var(--primaryDarken30) | ||||
|  | ||||
| 	> .add | ||||
| 		margin 8px 0 0 0 | ||||
| 		vertical-align top | ||||
| 		color $theme-color | ||||
| 		color var(--primary) | ||||
|  | ||||
| 	> .destroy | ||||
| 		position absolute | ||||
| 		top 0 | ||||
| 		right 0 | ||||
| 		padding 4px 8px | ||||
| 		color rgba($theme-color, 0.4) | ||||
| 		color var(--primaryAlpha04) | ||||
|  | ||||
| 		&:hover | ||||
| 			color rgba($theme-color, 0.6) | ||||
| 			color var(--primaryAlpha06) | ||||
|  | ||||
| 		&:active | ||||
| 			color darken($theme-color, 30%) | ||||
|  | ||||
| .mk-poll-editor[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .mk-poll-editor:not([data-darkmode]) | ||||
| 	root(false) | ||||
| 			color var(--primaryDarken30) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -67,10 +67,7 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
|  | ||||
| .mk-poll | ||||
| 	> ul | ||||
| 		display block | ||||
| 		margin 0 | ||||
| @@ -82,8 +79,8 @@ root(isDark) | ||||
| 			margin 4px 0 | ||||
| 			padding 4px 8px | ||||
| 			width 100% | ||||
| 			color isDark ? #fff : #000 | ||||
| 			border solid 1px isDark ? #5e636f : #eee | ||||
| 			color var(--pollChoiceText) | ||||
| 			border solid 1px var(--pollChoiceBorder) | ||||
| 			border-radius 4px | ||||
| 			overflow hidden | ||||
| 			cursor pointer | ||||
| @@ -99,7 +96,7 @@ root(isDark) | ||||
| 				top 0 | ||||
| 				left 0 | ||||
| 				height 100% | ||||
| 				background $theme-color | ||||
| 				background var(--primary) | ||||
| 				transition width 1s ease | ||||
|  | ||||
| 			> span | ||||
| @@ -110,7 +107,7 @@ root(isDark) | ||||
| 					margin-left 4px | ||||
|  | ||||
| 	> p | ||||
| 		color isDark ? #a3aebf : #000 | ||||
| 		color var(--text) | ||||
|  | ||||
| 		a | ||||
| 			color inherit | ||||
| @@ -125,10 +122,4 @@ root(isDark) | ||||
| 			&:active | ||||
| 				background transparent | ||||
|  | ||||
| .mk-poll[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .mk-poll:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -210,11 +210,9 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| $border-color = rgba(27, 31, 35, 0.15) | ||||
|  | ||||
| root(isDark) | ||||
| .mk-reaction-picker | ||||
| 	position initial | ||||
|  | ||||
| 	> .backdrop | ||||
| @@ -224,11 +222,11 @@ root(isDark) | ||||
| 		z-index 10000 | ||||
| 		width 100% | ||||
| 		height 100% | ||||
| 		background isDark ? rgba(#000, 0.4) : rgba(#000, 0.1) | ||||
| 		background var(--modalBackdrop) | ||||
| 		opacity 0 | ||||
|  | ||||
| 	> .popover | ||||
| 		$bgcolor = isDark ? #2c303c : #fff | ||||
| 		$bgcolor = var(--popupBg) | ||||
| 		position absolute | ||||
| 		z-index 10001 | ||||
| 		background $bgcolor | ||||
| @@ -281,8 +279,8 @@ root(isDark) | ||||
| 			margin 0 | ||||
| 			padding 8px 10px | ||||
| 			font-size 14px | ||||
| 			color isDark ? #d6dce2 : #586069 | ||||
| 			border-bottom solid 1px isDark ? #1c2023 : #e1e4e8 | ||||
| 			color var(--popupFg) | ||||
| 			border-bottom solid 1px var(--faceDivider) | ||||
|  | ||||
| 		> div | ||||
| 			padding 4px | ||||
| @@ -301,7 +299,7 @@ root(isDark) | ||||
| 						right 0 | ||||
| 						bottom 0 | ||||
| 						left 0 | ||||
| 						border 2px solid rgba($theme-color, 0.3) | ||||
| 						border 2px solid var(--primaryAlpha03) | ||||
| 						border-radius 4px | ||||
|  | ||||
| 			> button | ||||
| @@ -312,16 +310,10 @@ root(isDark) | ||||
| 				border-radius 2px | ||||
|  | ||||
| 				&:hover | ||||
| 					background isDark ? #252731 : #eee | ||||
| 					background var(--reactionPickerButtonHoverBg) | ||||
|  | ||||
| 				&:active | ||||
| 					background $theme-color | ||||
| 					background var(--primary) | ||||
| 					box-shadow inset 0 0.15em 0.3em rgba(27, 31, 35, 0.15) | ||||
|  | ||||
| .mk-reaction-picker[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .mk-reaction-picker:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -1,16 +1,16 @@ | ||||
| <template> | ||||
| <div class="mk-reactions-viewer"> | ||||
| 	<template v-if="reactions"> | ||||
| 		<span :class="{notReacted}" @click="react('like')" v-if="reactions.like"><mk-reaction-icon reaction="like"/><span>{{ reactions.like }}</span></span> | ||||
| 		<span :class="{notReacted}" @click="react('love')" v-if="reactions.love"><mk-reaction-icon reaction="love"/><span>{{ reactions.love }}</span></span> | ||||
| 		<span :class="{notReacted}" @click="react('laugh')" v-if="reactions.laugh"><mk-reaction-icon reaction="laugh"/><span>{{ reactions.laugh }}</span></span> | ||||
| 		<span :class="{notReacted}" @click="react('hmm')" v-if="reactions.hmm"><mk-reaction-icon reaction="hmm"/><span>{{ reactions.hmm }}</span></span> | ||||
| 		<span :class="{notReacted}" @click="react('surprise')" v-if="reactions.surprise"><mk-reaction-icon reaction="surprise"/><span>{{ reactions.surprise }}</span></span> | ||||
| 		<span :class="{notReacted}" @click="react('congrats')" v-if="reactions.congrats"><mk-reaction-icon reaction="congrats"/><span>{{ reactions.congrats }}</span></span> | ||||
| 		<span :class="{notReacted}" @click="react('angry')" v-if="reactions.angry"><mk-reaction-icon reaction="angry"/><span>{{ reactions.angry }}</span></span> | ||||
| 		<span :class="{notReacted}" @click="react('confused')" v-if="reactions.confused"><mk-reaction-icon reaction="confused"/><span>{{ reactions.confused }}</span></span> | ||||
| 		<span :class="{notReacted}" @click="react('rip')" v-if="reactions.rip"><mk-reaction-icon reaction="rip"/><span>{{ reactions.rip }}</span></span> | ||||
| 		<span :class="{notReacted}" @click="react('pudding')" v-if="reactions.pudding"><mk-reaction-icon reaction="pudding"/><span>{{ reactions.pudding }}</span></span> | ||||
| 		<span :class="{ reacted: note.myReaction == 'like' }" @click="react('like')" v-if="reactions.like"><mk-reaction-icon reaction="like"/><span>{{ reactions.like }}</span></span> | ||||
| 		<span :class="{ reacted: note.myReaction == 'love' }" @click="react('love')" v-if="reactions.love"><mk-reaction-icon reaction="love"/><span>{{ reactions.love }}</span></span> | ||||
| 		<span :class="{ reacted: note.myReaction == 'laugh' }" @click="react('laugh')" v-if="reactions.laugh"><mk-reaction-icon reaction="laugh"/><span>{{ reactions.laugh }}</span></span> | ||||
| 		<span :class="{ reacted: note.myReaction == 'hmm' }" @click="react('hmm')" v-if="reactions.hmm"><mk-reaction-icon reaction="hmm"/><span>{{ reactions.hmm }}</span></span> | ||||
| 		<span :class="{ reacted: note.myReaction == 'surprise' }" @click="react('surprise')" v-if="reactions.surprise"><mk-reaction-icon reaction="surprise"/><span>{{ reactions.surprise }}</span></span> | ||||
| 		<span :class="{ reacted: note.myReaction == 'congrats' }" @click="react('congrats')" v-if="reactions.congrats"><mk-reaction-icon reaction="congrats"/><span>{{ reactions.congrats }}</span></span> | ||||
| 		<span :class="{ reacted: note.myReaction == 'angry' }" @click="react('angry')" v-if="reactions.angry"><mk-reaction-icon reaction="angry"/><span>{{ reactions.angry }}</span></span> | ||||
| 		<span :class="{ reacted: note.myReaction == 'confused' }" @click="react('confused')" v-if="reactions.confused"><mk-reaction-icon reaction="confused"/><span>{{ reactions.confused }}</span></span> | ||||
| 		<span :class="{ reacted: note.myReaction == 'rip' }" @click="react('rip')" v-if="reactions.rip"><mk-reaction-icon reaction="rip"/><span>{{ reactions.rip }}</span></span> | ||||
| 		<span :class="{ reacted: note.myReaction == 'pudding' }" @click="react('pudding')" v-if="reactions.pudding"><mk-reaction-icon reaction="pudding"/><span>{{ reactions.pudding }}</span></span> | ||||
| 	</template> | ||||
| </div> | ||||
| </template> | ||||
| @@ -22,9 +22,6 @@ export default Vue.extend({ | ||||
| 	computed: { | ||||
| 		reactions(): number { | ||||
| 			return this.note.reactionCounts; | ||||
| 		}, | ||||
| 		notReacted(): boolean { | ||||
| 			return this.note.myReaction == null; | ||||
| 		} | ||||
| 	}, | ||||
| 	methods: { | ||||
| @@ -39,33 +36,43 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| root(isDark) | ||||
| 	$borderColor = isDark ? #5e6673 : #eee | ||||
| 	border-top dashed 1px $borderColor | ||||
| 	border-bottom dashed 1px $borderColor | ||||
| 	margin 4px 0 | ||||
| .mk-reactions-viewer | ||||
| 	margin 6px 0 | ||||
|  | ||||
| 	&:empty | ||||
| 		display none | ||||
|  | ||||
| 	> span | ||||
| 		margin-right 8px | ||||
| 		display inline-block | ||||
| 		height 32px | ||||
| 		margin-right 6px | ||||
| 		padding 0 6px | ||||
| 		border-radius 4px | ||||
|  | ||||
| 		&.notReacted | ||||
| 		* | ||||
| 			user-select none | ||||
| 			pointer-events none | ||||
|  | ||||
| 		&.reacted | ||||
| 			background var(--primary) | ||||
|  | ||||
| 			> span | ||||
| 				color var(--primaryForeground) | ||||
|  | ||||
| 		&:not(.reacted) | ||||
| 			cursor pointer | ||||
| 			background var(--reactionViewerButtonBg) | ||||
|  | ||||
| 			&:hover | ||||
| 				background var(--reactionViewerButtonHoverBg) | ||||
|  | ||||
| 		> .mk-reaction-icon | ||||
| 			font-size 1.4em | ||||
|  | ||||
| 		> span | ||||
| 			margin-left 4px | ||||
| 			font-size 1.2em | ||||
| 			color isDark ? #d1d5dc : #444 | ||||
|  | ||||
| .mk-reactions-viewer[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .mk-reactions-viewer:not([data-darkmode]) | ||||
| 	root(false) | ||||
| 			font-size 1.1em | ||||
| 			line-height 32px | ||||
| 			vertical-align middle | ||||
| 			color var(--text) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -1,16 +1,16 @@ | ||||
| <template> | ||||
| <form class="mk-signin" :class="{ signing }" @submit.prevent="onSubmit"> | ||||
| 	<div class="avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : null }" v-show="withAvatar"></div> | ||||
| 	<ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required @input="onUsernameChange"> | ||||
| 	<ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required @input="onUsernameChange" styl="fill"> | ||||
| 		<span>%i18n:@username%</span> | ||||
| 		<span slot="prefix">@</span> | ||||
| 		<span slot="suffix">@{{ host }}</span> | ||||
| 	</ui-input> | ||||
| 	<ui-input v-model="password" type="password" required> | ||||
| 	<ui-input v-model="password" type="password" required styl="fill"> | ||||
| 		<span>%i18n:@password%</span> | ||||
| 		<span slot="prefix">%fa:lock%</span> | ||||
| 	</ui-input> | ||||
| 	<ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="number" required/> | ||||
| 	<ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="number" required styl="fill"/> | ||||
| 	<ui-button type="submit" :disabled="signing">{{ signing ? '%i18n:@signing-in%' : '%i18n:@signin%' }}</ui-button> | ||||
| 	<p style="margin: 8px 0;">%i18n:@or% <a :href="`${apiUrl}/signin/twitter`">%i18n:@signin-with-twitter%</a></p> | ||||
| </form> | ||||
| @@ -56,7 +56,7 @@ export default Vue.extend({ | ||||
| 				username: this.username, | ||||
| 				password: this.password, | ||||
| 				token: this.user && this.user.twoFactorEnabled ? this.token : undefined | ||||
| 			}).then(() => { | ||||
| 			}, true).then(() => { | ||||
| 				location.reload(); | ||||
| 			}).catch(() => { | ||||
| 				alert('%i18n:@login-failed%'); | ||||
| @@ -68,7 +68,7 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
|  | ||||
| .mk-signin | ||||
| 	color #555 | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| <template> | ||||
| <form class="mk-signup" @submit.prevent="onSubmit" :autocomplete="Math.random()"> | ||||
| 	<template v-if="meta"> | ||||
| 		<ui-input v-if="meta.disableRegistration" v-model="invitationCode" type="text" :autocomplete="Math.random()" spellcheck="false" required> | ||||
| 		<ui-input v-if="meta.disableRegistration" v-model="invitationCode" type="text" :autocomplete="Math.random()" spellcheck="false" required styl="fill"> | ||||
| 			<span>%i18n:@invitation-code%</span> | ||||
| 			<span slot="prefix">%fa:id-card-alt%</span> | ||||
| 			<p slot="text" v-html="'%i18n:@invitation-info%'.replace('{}', meta.maintainer.url)"></p> | ||||
| 		</ui-input> | ||||
| 		<ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @input="onChangeUsername"> | ||||
| 		<ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @input="onChangeUsername" styl="fill"> | ||||
| 			<span>%i18n:@username%</span> | ||||
| 			<span slot="prefix">@</span> | ||||
| 			<span slot="suffix">@{{ host }}</span> | ||||
| @@ -18,7 +18,7 @@ | ||||
| 			<p slot="text" v-if="usernameState == 'min-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-short%</p> | ||||
| 			<p slot="text" v-if="usernameState == 'max-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-long%</p> | ||||
| 		</ui-input> | ||||
| 		<ui-input v-model="password" type="password" :autocomplete="Math.random()" required @input="onChangePassword" :with-password-meter="true"> | ||||
| 		<ui-input v-model="password" type="password" :autocomplete="Math.random()" required @input="onChangePassword" :with-password-meter="true" styl="fill"> | ||||
| 			<span>%i18n:@password%</span> | ||||
| 			<span slot="prefix">%fa:lock%</span> | ||||
| 			<div slot="text"> | ||||
| @@ -27,7 +27,7 @@ | ||||
| 				<p slot="text" v-if="passwordStrength == 'high'" style="color:#3CB7B5">%fa:check .fw% %i18n:@strong-password%</p> | ||||
| 			</div> | ||||
| 		</ui-input> | ||||
| 		<ui-input v-model="retypedPassword" type="password" :autocomplete="Math.random()" required @input="onChangePasswordRetype"> | ||||
| 		<ui-input v-model="retypedPassword" type="password" :autocomplete="Math.random()" required @input="onChangePasswordRetype" styl="fill"> | ||||
| 			<span>%i18n:@password% (%i18n:@retype%)</span> | ||||
| 			<span slot="prefix">%fa:lock%</span> | ||||
| 			<div slot="text"> | ||||
| @@ -131,11 +131,11 @@ export default Vue.extend({ | ||||
| 				password: this.password, | ||||
| 				invitationCode: this.invitationCode, | ||||
| 				'g-recaptcha-response': this.meta.recaptchaSitekey != null ? (window as any).grecaptcha.getResponse() : null | ||||
| 			}).then(() => { | ||||
| 			}, true).then(() => { | ||||
| 				(this as any).api('signin', { | ||||
| 					username: this.username, | ||||
| 					password: this.password | ||||
| 				}).then(() => { | ||||
| 				}, true).then(() => { | ||||
| 					location.href = '/'; | ||||
| 				}); | ||||
| 			}).catch(() => { | ||||
| @@ -151,7 +151,7 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
|  | ||||
| .mk-signup | ||||
| 	min-width 302px | ||||
|   | ||||
| @@ -1,14 +1,14 @@ | ||||
| <template> | ||||
| <div class="mk-stream-indicator"> | ||||
| 	<p v-if=" stream.state == 'initializing' "> | ||||
| 	<p v-if="stream.state == 'initializing'"> | ||||
| 		%fa:spinner .pulse% | ||||
| 		<span>%i18n:@connecting%<mk-ellipsis/></span> | ||||
| 	</p> | ||||
| 	<p v-if=" stream.state == 'reconnecting' "> | ||||
| 	<p v-if="stream.state == 'reconnecting'"> | ||||
| 		%fa:spinner .pulse% | ||||
| 		<span>%i18n:@reconnecting%<mk-ellipsis/></span> | ||||
| 	</p> | ||||
| 	<p v-if=" stream.state == 'connected' "> | ||||
| 	<p v-if="stream.state == 'connected'"> | ||||
| 		%fa:check% | ||||
| 		<span>%i18n:@connected%</span> | ||||
| 	</p> | ||||
|   | ||||
| @@ -1,199 +0,0 @@ | ||||
| <template> | ||||
| <div | ||||
| 	class="mk-switch" | ||||
| 	:class="{ disabled, checked }" | ||||
| 	role="switch" | ||||
| 	:aria-checked="checked" | ||||
| 	:aria-disabled="disabled" | ||||
| 	@click="switchValue" | ||||
| 	@mouseover="mouseenter" | ||||
| > | ||||
| 	<input | ||||
| 		type="checkbox" | ||||
| 		@change="handleChange" | ||||
| 		ref="input" | ||||
| 		:disabled="disabled" | ||||
| 		@keydown.enter="switchValue" | ||||
| 	> | ||||
| 	<span class="button"> | ||||
| 		<span :style="{ transform }"></span> | ||||
| 	</span> | ||||
| 	<span class="label"> | ||||
| 		<span :aria-hidden="!checked">{{ text }}</span> | ||||
| 		<p :aria-hidden="!checked"> | ||||
| 			<slot></slot> | ||||
| 		</p> | ||||
| 	</span> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| export default Vue.extend({ | ||||
| 	props: { | ||||
| 		value: { | ||||
| 			type: Boolean, | ||||
| 			default: false | ||||
| 		}, | ||||
| 		disabled: { | ||||
| 			type: Boolean, | ||||
| 			default: false | ||||
| 		}, | ||||
| 		text: String | ||||
| 	},/* | ||||
| 	created() { | ||||
| 		if (!~[true, false].indexOf(this.value)) { | ||||
| 			this.$emit('input', false); | ||||
| 		} | ||||
| 	},*/ | ||||
| 	computed: { | ||||
| 		checked(): boolean { | ||||
| 			return this.value; | ||||
| 		}, | ||||
| 		transform(): string { | ||||
| 			return this.checked ? 'translate3d(20px, 0, 0)' : ''; | ||||
| 		} | ||||
| 	}, | ||||
| 	watch: { | ||||
| 		value() { | ||||
| 			(this.$el).style.transition = 'all 0.3s'; | ||||
| 			(this.$refs.input as any).checked = this.checked; | ||||
| 		} | ||||
| 	}, | ||||
| 	mounted() { | ||||
| 		(this.$refs.input as any).checked = this.checked; | ||||
| 	}, | ||||
| 	methods: { | ||||
| 		mouseenter() { | ||||
| 			(this.$el).style.transition = 'all 0s'; | ||||
| 		}, | ||||
| 		handleChange() { | ||||
| 			(this.$el).style.transition = 'all 0.3s'; | ||||
| 			this.$emit('input', !this.checked); | ||||
| 			this.$emit('change', !this.checked); | ||||
| 			this.$nextTick(() => { | ||||
| 				// set input's checked property | ||||
| 				// in case parent refuses to change component's value | ||||
| 				(this.$refs.input as any).checked = this.checked; | ||||
| 			}); | ||||
| 		}, | ||||
| 		switchValue() { | ||||
| 			!this.disabled && this.handleChange(); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
| 	display flex | ||||
| 	margin 12px 0 | ||||
| 	cursor pointer | ||||
| 	transition all 0.3s | ||||
|  | ||||
| 	> * | ||||
| 		user-select none | ||||
|  | ||||
| 	&.disabled | ||||
| 		opacity 0.6 | ||||
| 		cursor not-allowed | ||||
|  | ||||
| 	&.checked | ||||
| 		> .button | ||||
| 			background-color $theme-color | ||||
| 			border-color $theme-color | ||||
|  | ||||
| 		> .label | ||||
| 			> span | ||||
| 				color $theme-color | ||||
|  | ||||
| 		&:hover | ||||
| 			> .label | ||||
| 				> span | ||||
| 					color darken($theme-color, 10%) | ||||
|  | ||||
| 			> .button | ||||
| 				background darken($theme-color, 10%) | ||||
| 				border-color darken($theme-color, 10%) | ||||
|  | ||||
| 	&:hover | ||||
| 		> .label | ||||
| 			> span | ||||
| 				color isDark ? #fff : #2e3338 | ||||
|  | ||||
| 		> .button | ||||
| 			$color = isDark ? #15181d : #ced2da | ||||
| 			background $color | ||||
| 			border-color $color | ||||
|  | ||||
| 	> input | ||||
| 		position absolute | ||||
| 		width 0 | ||||
| 		height 0 | ||||
| 		opacity 0 | ||||
| 		margin 0 | ||||
|  | ||||
| 		&:focus + .button | ||||
| 			&:after | ||||
| 				content "" | ||||
| 				pointer-events none | ||||
| 				position absolute | ||||
| 				top -5px | ||||
| 				right -5px | ||||
| 				bottom -5px | ||||
| 				left -5px | ||||
| 				border 2px solid rgba($theme-color, 0.3) | ||||
| 				border-radius 14px | ||||
|  | ||||
| 	> .button | ||||
| 		$color = isDark ? #1c1f25 : #dcdfe6 | ||||
|  | ||||
| 		display inline-block | ||||
| 		margin 0 | ||||
| 		width 40px | ||||
| 		min-width 40px | ||||
| 		height 20px | ||||
| 		min-height 20px | ||||
| 		background $color | ||||
| 		border 1px solid $color | ||||
| 		outline none | ||||
| 		border-radius 10px | ||||
| 		transition inherit | ||||
|  | ||||
| 		> * | ||||
| 			position absolute | ||||
| 			top 1px | ||||
| 			left 1px | ||||
| 			border-radius 100% | ||||
| 			transition transform 0.3s | ||||
| 			width 16px | ||||
| 			height 16px | ||||
| 			background-color #fff | ||||
|  | ||||
| 	> .label | ||||
| 		margin-left 8px | ||||
| 		display block | ||||
| 		font-size 15px | ||||
| 		cursor pointer | ||||
| 		transition inherit | ||||
|  | ||||
| 		> span | ||||
| 			display block | ||||
| 			line-height 20px | ||||
| 			color isDark ? #c4ccd2 : #4a535a | ||||
| 			transition inherit | ||||
|  | ||||
| 		> p | ||||
| 			margin 0 | ||||
| 			//font-size 90% | ||||
| 			color isDark ? #78858e : #9daab3 | ||||
|  | ||||
| .mk-switch[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .mk-switch:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
| @@ -63,7 +63,7 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| root(isDark) | ||||
| .jtivnzhfwquxpsfidertopbmwmchmnmo | ||||
| 	height 100% | ||||
| 	width 100% | ||||
|  | ||||
| @@ -81,10 +81,4 @@ root(isDark) | ||||
| 		height 100% | ||||
| 		width 100% | ||||
|  | ||||
| .jtivnzhfwquxpsfidertopbmwmchmnmo[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .jtivnzhfwquxpsfidertopbmwmchmnmo:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
							
								
								
									
										308
									
								
								src/client/app/common/views/components/theme.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										308
									
								
								src/client/app/common/views/components/theme.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,308 @@ | ||||
| <template> | ||||
| <div class="nicnklzforebnpfgasiypmpdaaglujqm"> | ||||
| 	<label> | ||||
| 		<span>%i18n:@light-theme%</span> | ||||
| 		<ui-select v-model="light" placeholder="%i18n:@light-theme%"> | ||||
| 			<optgroup label="%i18n:@light-themes%"> | ||||
| 				<option v-for="x in lightThemes" :value="x.id" :key="x.id">{{ x.name }}</option> | ||||
| 			</optgroup> | ||||
| 			<optgroup label="%i18n:@dark-themes%"> | ||||
| 				<option v-for="x in darkThemes" :value="x.id" :key="x.id">{{ x.name }}</option> | ||||
| 			</optgroup> | ||||
| 		</ui-select> | ||||
| 	</label> | ||||
|  | ||||
| 	<label> | ||||
| 		<span>%i18n:@dark-theme%</span> | ||||
| 		<ui-select v-model="dark" placeholder="%i18n:@dark-theme%"> | ||||
| 			<optgroup label="%i18n:@dark-themes%"> | ||||
| 				<option v-for="x in darkThemes" :value="x.id" :key="x.id">{{ x.name }}</option> | ||||
| 			</optgroup> | ||||
| 			<optgroup label="%i18n:@light-themes%"> | ||||
| 				<option v-for="x in lightThemes" :value="x.id" :key="x.id">{{ x.name }}</option> | ||||
| 			</optgroup> | ||||
| 		</ui-select> | ||||
| 	</label> | ||||
|  | ||||
| 	<details class="creator"> | ||||
| 		<summary>%fa:palette% %i18n:@create-a-theme%</summary> | ||||
| 		<div> | ||||
| 			<span>%i18n:@base-theme%:</span> | ||||
| 			<ui-radio v-model="myThemeBase" value="light">%i18n:@base-theme-light%</ui-radio> | ||||
| 			<ui-radio v-model="myThemeBase" value="dark">%i18n:@base-theme-dark%</ui-radio> | ||||
| 		</div> | ||||
| 		<div> | ||||
| 			<ui-input v-model="myThemeName"> | ||||
| 				<span>%i18n:@theme-name%</span> | ||||
| 			</ui-input> | ||||
| 			<ui-textarea v-model="myThemeDesc"> | ||||
| 				<span>%i18n:@desc%</span> | ||||
| 			</ui-textarea> | ||||
| 		</div> | ||||
| 		<div> | ||||
| 			<div style="padding-bottom:8px;">%i18n:@primary-color%:</div> | ||||
| 			<color-picker v-model="myThemePrimary"/> | ||||
| 		</div> | ||||
| 		<div> | ||||
| 			<div style="padding-bottom:8px;">%i18n:@secondary-color%:</div> | ||||
| 			<color-picker v-model="myThemeSecondary"/> | ||||
| 		</div> | ||||
| 		<div> | ||||
| 			<div style="padding-bottom:8px;">%i18n:@text-color%:</div> | ||||
| 			<color-picker v-model="myThemeText"/> | ||||
| 		</div> | ||||
| 		<ui-button @click="preview()">%fa:eye% %i18n:@preview-created-theme%</ui-button> | ||||
| 		<ui-button primary @click="gen()">%fa:save R% %i18n:@save-created-theme%</ui-button> | ||||
| 	</details> | ||||
|  | ||||
| 	<details> | ||||
| 		<summary>%fa:download% %i18n:@install-a-theme%</summary> | ||||
| 		<ui-button @click="import_()">%fa:file-import% %i18n:@import%</ui-button> | ||||
| 		<input ref="file" type="file" accept=".misskeytheme" style="display:none;" @change="onUpdateImportFile"/> | ||||
| 		<p>%i18n:@import-by-code%:</p> | ||||
| 		<ui-textarea v-model="installThemeCode"> | ||||
| 			<span>%i18n:@theme-code%</span> | ||||
| 		</ui-textarea> | ||||
| 		<ui-button @click="() => install(this.installThemeCode)">%fa:check% %i18n:@install%</ui-button> | ||||
| 	</details> | ||||
|  | ||||
| 	<details> | ||||
| 		<summary>%fa:folder-open% %i18n:@installed-themes%</summary> | ||||
| 		<ui-select v-model="selectedInstalledThemeId" placeholder="%i18n:@select-theme%"> | ||||
| 			<option v-for="x in installedThemes" :value="x.id" :key="x.id">{{ x.name }}</option> | ||||
| 		</ui-select> | ||||
| 		<template v-if="selectedInstalledTheme"> | ||||
| 			<ui-input readonly :value="selectedInstalledTheme.author"> | ||||
| 				<span>%i18n:@author%</span> | ||||
| 			</ui-input> | ||||
| 			<ui-textarea v-if="selectedInstalledTheme.desc" readonly :value="selectedInstalledTheme.desc"> | ||||
| 				<span>%i18n:@desc%</span> | ||||
| 			</ui-textarea> | ||||
| 			<ui-textarea readonly :value="selectedInstalledThemeCode"> | ||||
| 				<span>%i18n:@theme-code%</span> | ||||
| 			</ui-textarea> | ||||
| 			<ui-button @click="export_()" link :download="`${selectedInstalledTheme.name}.misskeytheme`" ref="export">%fa:box% %i18n:@export%</ui-button> | ||||
| 			<ui-button @click="uninstall()">%fa:trash-alt R% %i18n:@uninstall%</ui-button> | ||||
| 		</template> | ||||
| 	</details> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import { lightTheme, darkTheme, builtinThemes, applyTheme, Theme } from '../../../theme'; | ||||
| import { Chrome } from 'vue-color'; | ||||
| import * as uuid from 'uuid'; | ||||
| import * as tinycolor from 'tinycolor2'; | ||||
| import * as JSON5 from 'json5'; | ||||
|  | ||||
| // 後方互換性のため | ||||
| function convertOldThemedefinition(t) { | ||||
| 	const t2 = { | ||||
| 		id: t.meta.id, | ||||
| 		name: t.meta.name, | ||||
| 		author: t.meta.author, | ||||
| 		base: t.meta.base, | ||||
| 		vars: t.meta.vars, | ||||
| 		props: t | ||||
| 	}; | ||||
| 	delete t2.props.meta; | ||||
| 	return t2; | ||||
| } | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	components: { | ||||
| 		ColorPicker: Chrome | ||||
| 	}, | ||||
|  | ||||
| 	data() { | ||||
| 		return { | ||||
| 			installThemeCode: null, | ||||
| 			selectedInstalledThemeId: null, | ||||
| 			myThemeBase: 'light', | ||||
| 			myThemeName: '', | ||||
| 			myThemeDesc: '', | ||||
| 			myThemePrimary: lightTheme.vars.primary, | ||||
| 			myThemeSecondary: lightTheme.vars.secondary, | ||||
| 			myThemeText: lightTheme.vars.text | ||||
| 		}; | ||||
| 	}, | ||||
|  | ||||
| 	computed: { | ||||
| 		themes(): Theme[] { | ||||
| 			return builtinThemes.concat(this.$store.state.device.themes); | ||||
| 		}, | ||||
|  | ||||
| 		darkThemes(): Theme[] { | ||||
| 			return this.themes.filter(t => t.base == 'dark' || t.kind == 'dark'); | ||||
| 		}, | ||||
|  | ||||
| 		lightThemes(): Theme[] { | ||||
| 			return this.themes.filter(t => t.base == 'light' || t.kind == 'light'); | ||||
| 		}, | ||||
|  | ||||
| 		installedThemes(): Theme[] { | ||||
| 			return this.$store.state.device.themes; | ||||
| 		}, | ||||
|  | ||||
| 		light: { | ||||
| 			get() { return this.$store.state.device.lightTheme; }, | ||||
| 			set(value) { this.$store.commit('device/set', { key: 'lightTheme', value }); } | ||||
| 		}, | ||||
|  | ||||
| 		dark: { | ||||
| 			get() { return this.$store.state.device.darkTheme; }, | ||||
| 			set(value) { this.$store.commit('device/set', { key: 'darkTheme', value }); } | ||||
| 		}, | ||||
|  | ||||
| 		selectedInstalledTheme() { | ||||
| 			if (this.selectedInstalledThemeId == null) return null; | ||||
| 			return this.installedThemes.find(x => x.id == this.selectedInstalledThemeId); | ||||
| 		}, | ||||
|  | ||||
| 		selectedInstalledThemeCode() { | ||||
| 			if (this.selectedInstalledTheme == null) return null; | ||||
| 			return JSON5.stringify(this.selectedInstalledTheme, null, '\t'); | ||||
| 		}, | ||||
|  | ||||
| 		myTheme(): any { | ||||
| 			return { | ||||
| 				name: this.myThemeName, | ||||
| 				author: this.$store.state.i.username, | ||||
| 				desc: this.myThemeDesc, | ||||
| 				base: this.myThemeBase, | ||||
| 				vars: { | ||||
| 					primary: tinycolor(typeof this.myThemePrimary == 'string' ? this.myThemePrimary : this.myThemePrimary.rgba).toRgbString(), | ||||
| 					secondary: tinycolor(typeof this.myThemeSecondary == 'string' ? this.myThemeSecondary : this.myThemeSecondary.rgba).toRgbString(), | ||||
| 					text: tinycolor(typeof this.myThemeText == 'string' ? this.myThemeText : this.myThemeText.rgba).toRgbString() | ||||
| 				} | ||||
| 			}; | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	watch: { | ||||
| 		myThemeBase(v) { | ||||
| 			const theme = v == 'light' ? lightTheme : darkTheme; | ||||
| 			this.myThemePrimary = theme.vars.primary; | ||||
| 			this.myThemeSecondary = theme.vars.secondary; | ||||
| 			this.myThemeText = theme.vars.text; | ||||
| 		} | ||||
| 	}, | ||||
|  | ||||
| 	beforeCreate() { | ||||
| 		// migrate old theme definitions | ||||
| 		// 後方互換性のため | ||||
| 		this.$store.commit('device/set', { | ||||
| 			key: 'themes', value: this.$store.state.device.themes.map(t => { | ||||
| 				if (t.id == null) { | ||||
| 					return convertOldThemedefinition(t); | ||||
| 				} else { | ||||
| 					return t; | ||||
| 				} | ||||
| 			}) | ||||
| 		}); | ||||
| 	}, | ||||
|  | ||||
| 	methods: { | ||||
| 		install(code) { | ||||
| 			let theme; | ||||
|  | ||||
| 			try { | ||||
| 				theme = JSON5.parse(code); | ||||
| 			} catch (e) { | ||||
| 				alert('%i18n:@invalid-theme%'); | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			// 後方互換性のため | ||||
| 			if (theme.id == null && theme.meta != null) { | ||||
| 				theme = convertOldThemedefinition(theme); | ||||
| 			} | ||||
|  | ||||
| 			if (theme.id == null) { | ||||
| 				alert('%i18n:@invalid-theme%'); | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			if (this.$store.state.device.themes.some(t => t.id == theme.id)) { | ||||
| 				alert('%i18n:@already-installed%'); | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			const themes = this.$store.state.device.themes.concat(theme); | ||||
| 			this.$store.commit('device/set', { | ||||
| 				key: 'themes', value: themes | ||||
| 			}); | ||||
|  | ||||
| 			alert('%i18n:@installed%'.replace('{}', theme.name)); | ||||
| 		}, | ||||
|  | ||||
| 		uninstall() { | ||||
| 			const theme = this.selectedInstalledTheme; | ||||
| 			const themes = this.$store.state.device.themes.filter(t => t.id != theme.id); | ||||
| 			this.$store.commit('device/set', { | ||||
| 				key: 'themes', value: themes | ||||
| 			}); | ||||
| 			alert('%i18n:@uninstalled%'.replace('{}', theme.name)); | ||||
| 		}, | ||||
|  | ||||
| 		import_() { | ||||
| 			(this.$refs.file as any).click(); | ||||
| 		} | ||||
|  | ||||
| 		export_() { | ||||
| 			const blob = new Blob([this.selectedInstalledThemeCode], { | ||||
| 				type: 'application/json5' | ||||
| 			}); | ||||
| 			this.$refs.export.$el.href = window.URL.createObjectURL(blob); | ||||
| 		}, | ||||
|  | ||||
| 		onUpdateImportFile() { | ||||
| 			const f = (this.$refs.file as any).files[0]; | ||||
|  | ||||
| 			const reader = new FileReader(); | ||||
|  | ||||
| 			reader.onload = e => { | ||||
| 				this.install(e.target.result); | ||||
| 			}; | ||||
|  | ||||
| 			reader.readAsText(f); | ||||
| 		}, | ||||
|  | ||||
| 		preview() { | ||||
| 			applyTheme(this.myTheme, false); | ||||
| 		}, | ||||
|  | ||||
| 		gen() { | ||||
| 			const theme = this.myTheme; | ||||
| 			if (theme.name == null || theme.name.trim() == '') { | ||||
| 				alert('%i18n:@theme-name-required%'); | ||||
| 				return; | ||||
| 			} | ||||
| 			theme.id = uuid(); | ||||
| 			const themes = this.$store.state.device.themes.concat(theme); | ||||
| 			this.$store.commit('device/set', { | ||||
| 				key: 'themes', value: themes | ||||
| 			}); | ||||
| 			alert('%i18n:@saved%'); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| .nicnklzforebnpfgasiypmpdaaglujqm | ||||
| 	> details | ||||
| 		border-top solid 1px var(--faceDivider) | ||||
|  | ||||
| 		> summary | ||||
| 			padding 16px 0 | ||||
|  | ||||
| 		> *:last-child | ||||
| 			margin-bottom 16px | ||||
|  | ||||
| 	> .creator | ||||
| 		> div | ||||
| 			padding 16px 0 | ||||
| 			border-bottom solid 1px var(--faceDivider) | ||||
| </style> | ||||
| @@ -49,13 +49,14 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| root(isDark) | ||||
| .csqvmxybqbycalfhkxvyfrgbrdalkaoc | ||||
| 	> .fetching | ||||
| 	> .empty | ||||
| 		margin 0 | ||||
| 		padding 16px | ||||
| 		text-align center | ||||
| 		color #aaa | ||||
| 		color var(--text) | ||||
| 		opacity 0.7 | ||||
|  | ||||
| 		> [data-fa] | ||||
| 			margin-right 4px | ||||
| @@ -70,13 +71,13 @@ root(isDark) | ||||
| 			padding 14px 16px | ||||
|  | ||||
| 			&:not(:last-child) | ||||
| 				border-bottom solid 1px isDark ? #393f4f : #eee | ||||
| 				border-bottom solid 1px var(--faceDivider) | ||||
|  | ||||
| 			> .tag | ||||
| 				flex 1 | ||||
| 				overflow hidden | ||||
| 				font-size 14px | ||||
| 				color isDark ? #9baec8 : #65727b | ||||
| 				color var(--text) | ||||
|  | ||||
| 				> a | ||||
| 					display block | ||||
| @@ -94,10 +95,4 @@ root(isDark) | ||||
| 			> .chart | ||||
| 				height 30px | ||||
|  | ||||
| .csqvmxybqbycalfhkxvyfrgbrdalkaoc[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .csqvmxybqbycalfhkxvyfrgbrdalkaoc:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -1,9 +1,7 @@ | ||||
| <template> | ||||
| <div class="ui-button" :class="[styl]"> | ||||
| 	<button :type="type" @click="$emit('click')"> | ||||
| <component class="dmtdnykelhudezerjlfpbhgovrgnqqgr" :is="link ? 'a' : 'button'" :class="[styl, { inline, primary }]" :type="type" @click="$emit('click')"> | ||||
| 	<slot></slot> | ||||
| 	</button> | ||||
| </div> | ||||
| </component> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts"> | ||||
| @@ -13,70 +11,100 @@ export default Vue.extend({ | ||||
| 		type: { | ||||
| 			type: String, | ||||
| 			required: false | ||||
| 		}, | ||||
| 		primary: { | ||||
| 			type: Boolean, | ||||
| 			required: false, | ||||
| 			default: false | ||||
| 		}, | ||||
| 		inline: { | ||||
| 			type: Boolean, | ||||
| 			required: false, | ||||
| 			default: false | ||||
| 		}, | ||||
| 		link: { | ||||
| 			type: Boolean, | ||||
| 			required: false, | ||||
| 			default: false | ||||
| 		} | ||||
| 	}, | ||||
| 	data() { | ||||
| 		return { | ||||
| 			styl: 'fill' | ||||
| 		}; | ||||
| 	}, | ||||
| 	inject: { | ||||
| 		isCardChild: { default: false } | ||||
| 	}, | ||||
| 	created() { | ||||
| 		if (this.isCardChild) { | ||||
| 			this.styl = 'line'; | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark, fill) | ||||
| 	> button | ||||
| .dmtdnykelhudezerjlfpbhgovrgnqqgr | ||||
| 	display block | ||||
| 	width 100% | ||||
| 	margin 0 | ||||
| 		padding 0 | ||||
| 		font-weight bold | ||||
| 	padding 8px | ||||
| 	text-align center | ||||
| 	font-weight normal | ||||
| 	font-size 16px | ||||
| 		line-height 44px | ||||
| 	border none | ||||
| 	border-radius 6px | ||||
| 	outline none | ||||
| 	box-shadow none | ||||
| 	text-decoration none | ||||
| 	user-select none | ||||
|  | ||||
| 		if fill | ||||
| 			color $theme-color-foreground | ||||
| 			background $theme-color | ||||
| 	* | ||||
| 		pointer-events none | ||||
|  | ||||
| 	&:focus | ||||
| 		&:after | ||||
| 			content "" | ||||
| 			pointer-events none | ||||
| 			position absolute | ||||
| 			top -5px | ||||
| 			right -5px | ||||
| 			bottom -5px | ||||
| 			left -5px | ||||
| 			border 2px solid var(--primaryAlpha03) | ||||
| 			border-radius 10px | ||||
|  | ||||
| 	&:not(.inline) + .dmtdnykelhudezerjlfpbhgovrgnqqgr | ||||
| 		margin-top 16px | ||||
|  | ||||
| 	&.inline | ||||
| 		display inline-block | ||||
| 		width auto | ||||
|  | ||||
| 	&.primary | ||||
| 		font-weight bold | ||||
|  | ||||
| 	&.fill | ||||
| 		color var(--text) | ||||
| 		background var(--buttonBg) | ||||
|  | ||||
| 		&:hover | ||||
| 				background lighten($theme-color, 5%) | ||||
| 			background var(--buttonHoverBg) | ||||
|  | ||||
| 		&:active | ||||
| 				background darken($theme-color, 5%) | ||||
| 		else | ||||
| 			color $theme-color | ||||
| 			background var(--buttonActiveBg) | ||||
|  | ||||
| 		&.primary | ||||
| 			color var(--primaryForeground) | ||||
| 			background var(--primary) | ||||
|  | ||||
| 			&:hover | ||||
| 				background var(--primaryLighten5) | ||||
|  | ||||
| 			&:active | ||||
| 				background var(--primaryDarken5) | ||||
|  | ||||
| 	&:not(.fill) | ||||
| 		color var(--primary) | ||||
| 		background none | ||||
|  | ||||
| 		&:hover | ||||
| 				color darken($theme-color, 5%) | ||||
| 			color var(--primaryDarken5) | ||||
|  | ||||
| 		&:active | ||||
| 				background rgba($theme-color, 0.3) | ||||
|  | ||||
| .ui-button[data-darkmode] | ||||
| 	&.fill | ||||
| 		root(true, true) | ||||
| 	&:not(.fill) | ||||
| 		root(true, false) | ||||
|  | ||||
| .ui-button:not([data-darkmode]) | ||||
| 	&.fill | ||||
| 		root(false, true) | ||||
| 	&:not(.fill) | ||||
| 		root(false, false) | ||||
| 			background var(--primaryAlpha03) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -20,26 +20,24 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
| .ui-card | ||||
| 	margin 16px | ||||
| 	color isDark ? #fff : #000 | ||||
| 	background isDark ? #282C37 : #fff | ||||
| 	color var(--faceText) | ||||
| 	background var(--face) | ||||
| 	box-shadow 0 3px 1px -2px rgba(#000, 0.2), 0 2px 2px 0 rgba(#000, 0.14), 0 1px 5px 0 rgba(#000, 0.12) | ||||
|  | ||||
| 	> header | ||||
| 		padding 16px | ||||
| 		font-weight bold | ||||
| 		font-size 20px | ||||
| 		color isDark ? #fff : #444 | ||||
| 		color var(--faceText) | ||||
|  | ||||
| 		@media (min-width 500px) | ||||
| 			padding 24px 32px | ||||
|  | ||||
| 	> section | ||||
| 		padding 20px 16px | ||||
| 		border-top solid 1px isDark ? rgba(#000, 0.3) : rgba(#000, 0.1) | ||||
| 		border-top solid 1px var(--faceDivider) | ||||
|  | ||||
| 		@media (min-width 500px) | ||||
| 			padding 32px | ||||
| @@ -50,12 +48,5 @@ root(isDark) | ||||
| 		> header | ||||
| 			margin-bottom 16px | ||||
| 			font-weight bold | ||||
| 			color isDark ? #fff : #444 | ||||
|  | ||||
| .ui-card[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .ui-card:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| 			color var(--faceText) | ||||
| </style> | ||||
|   | ||||
| @@ -19,7 +19,7 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
|  | ||||
| .ui-form | ||||
| 	> fieldset | ||||
|   | ||||
| @@ -25,9 +25,7 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
| .nvemkhtwcnnpkdrwfcbzuwhfulejhmzg | ||||
| 	display inline-block | ||||
|  | ||||
| 	& + .nvemkhtwcnnpkdrwfcbzuwhfulejhmzg | ||||
| @@ -38,11 +36,11 @@ root(isDark) | ||||
| 		margin 0 | ||||
| 		padding 12px 20px | ||||
| 		font-size 14px | ||||
| 		border 1px solid isDark ? #6d727d : #dcdfe6 | ||||
| 		border 1px solid var(--formButtonBorder) | ||||
| 		border-radius 4px | ||||
| 		outline none | ||||
| 		box-shadow none | ||||
| 		color isDark ? #fff : #606266 | ||||
| 		color var(--text) | ||||
| 		transition 0.1s | ||||
|  | ||||
| 		* | ||||
| @@ -50,40 +48,34 @@ root(isDark) | ||||
|  | ||||
| 		&:hover | ||||
| 		&:focus | ||||
| 			color $theme-color | ||||
| 			background rgba($theme-color, isDark ? 0.2 : 0.12) | ||||
| 			border-color rgba($theme-color, isDark ? 0.5 : 0.3) | ||||
| 			color var(--primary) | ||||
| 			background var(--formButtonHoverBg) | ||||
| 			border-color var(--formButtonHoverBorder) | ||||
|  | ||||
| 		&:active | ||||
| 			color darken($theme-color, 20%) | ||||
| 			background rgba($theme-color, 0.12) | ||||
| 			border-color $theme-color | ||||
| 			color var(--primaryDarken20) | ||||
| 			background var(--formButtonActiveBg) | ||||
| 			border-color var(--primary) | ||||
| 			transition all 0s | ||||
|  | ||||
| 	&.primary | ||||
| 		> button | ||||
| 			border 1px solid $theme-color | ||||
| 			background $theme-color | ||||
| 			color $theme-color-foreground | ||||
| 			border 1px solid var(--primary) | ||||
| 			background var(--primary) | ||||
| 			color var(--primaryForeground) | ||||
|  | ||||
| 			&:hover | ||||
| 			&:focus | ||||
| 				background lighten($theme-color, 20%) | ||||
| 				border-color lighten($theme-color, 20%) | ||||
| 				background var(--primaryLighten20) | ||||
| 				border-color var(--primaryLighten20) | ||||
|  | ||||
| 			&:active | ||||
| 				background darken($theme-color, 20%) | ||||
| 				border-color darken($theme-color, 20%) | ||||
| 				background var(--primaryDarken20) | ||||
| 				border-color var(--primaryDarken20) | ||||
| 				transition all 0s | ||||
|  | ||||
| 	&.round | ||||
| 		> button | ||||
| 			border-radius 64px | ||||
|  | ||||
| .nvemkhtwcnnpkdrwfcbzuwhfulejhmzg[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .nvemkhtwcnnpkdrwfcbzuwhfulejhmzg:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -49,9 +49,7 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
| .uywduthvrdnlpsvsjkqigicixgyfctto | ||||
| 	display inline-flex | ||||
| 	margin 0 16px 0 0 | ||||
| 	cursor pointer | ||||
| @@ -62,7 +60,7 @@ root(isDark) | ||||
|  | ||||
| 	&:hover | ||||
| 		> .button | ||||
| 			border solid 2px isDark ? rgba(#fff, 0.7) : rgba(#000, 0.54) | ||||
| 			border solid 2px var(--inputLabel) | ||||
|  | ||||
| 	&.disabled | ||||
| 		opacity 0.6 | ||||
| @@ -70,15 +68,15 @@ root(isDark) | ||||
|  | ||||
| 	&.checked | ||||
| 		> .button | ||||
| 			border-color $theme-color | ||||
| 			border-color var(--primary) | ||||
|  | ||||
| 			&:after | ||||
| 				background-color $theme-color | ||||
| 				background-color var(--primary) | ||||
| 				transform scale(1) | ||||
| 				opacity 1 | ||||
|  | ||||
| 		> .label | ||||
| 			color $theme-color | ||||
| 			color var(--primary) | ||||
|  | ||||
| 	> input | ||||
| 		position absolute | ||||
| @@ -93,7 +91,7 @@ root(isDark) | ||||
| 		width 20px | ||||
| 		height 20px | ||||
| 		background none | ||||
| 		border solid 2px isDark ? rgba(#fff, 0.6) : rgba(#000, 0.4) | ||||
| 		border solid 2px var(--radioBorder) | ||||
| 		border-radius 100% | ||||
| 		transition inherit | ||||
|  | ||||
| @@ -117,10 +115,4 @@ root(isDark) | ||||
| 		line-height 20px | ||||
| 		cursor pointer | ||||
|  | ||||
| .uywduthvrdnlpsvsjkqigicixgyfctto[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .uywduthvrdnlpsvsjkqigicixgyfctto:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -71,14 +71,18 @@ export default Vue.extend({ | ||||
| 			type: Boolean, | ||||
| 			required: false, | ||||
| 			default: false | ||||
| 		}, | ||||
| 		styl: { | ||||
| 			type: String, | ||||
| 			required: false, | ||||
| 			default: 'line' | ||||
| 		} | ||||
| 	}, | ||||
| 	data() { | ||||
| 		return { | ||||
| 			v: this.value, | ||||
| 			focused: false, | ||||
| 			passwordStrength: '', | ||||
| 			styl: 'fill' | ||||
| 			passwordStrength: '' | ||||
| 		}; | ||||
| 	}, | ||||
| 	computed: { | ||||
| @@ -117,14 +121,6 @@ export default Vue.extend({ | ||||
| 			} | ||||
| 		} | ||||
| 	}, | ||||
| 	inject: { | ||||
| 		isCardChild: { default: false } | ||||
| 	}, | ||||
| 	created() { | ||||
| 		if (this.isCardChild) { | ||||
| 			this.styl = 'line'; | ||||
| 		} | ||||
| 	}, | ||||
| 	mounted() { | ||||
| 		if (this.$refs.prefix) { | ||||
| 			this.$refs.label.style.left = (this.$refs.prefix.offsetLeft + this.$refs.prefix.offsetWidth) + 'px'; | ||||
| @@ -155,9 +151,7 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark, fill) | ||||
| root(fill) | ||||
| 	margin 32px 0 | ||||
|  | ||||
| 	> .icon | ||||
| @@ -167,7 +161,7 @@ root(isDark, fill) | ||||
| 		width 24px | ||||
| 		text-align center | ||||
| 		line-height 32px | ||||
| 		color isDark ? rgba(#fff, 0.7) : rgba(#000, 0.54) | ||||
| 		color var(--inputLabel) | ||||
|  | ||||
| 		&:not(:empty) + .input | ||||
| 			margin-left 28px | ||||
| @@ -183,7 +177,7 @@ root(isDark, fill) | ||||
| 				left 0 | ||||
| 				right 0 | ||||
| 				height 1px | ||||
| 				background isDark ? rgba(#fff, 0.7) : rgba(#000, 0.42) | ||||
| 				background var(--inputBorder) | ||||
|  | ||||
| 			&:after | ||||
| 				content '' | ||||
| @@ -193,7 +187,7 @@ root(isDark, fill) | ||||
| 				left 0 | ||||
| 				right 0 | ||||
| 				height 2px | ||||
| 				background $theme-color | ||||
| 				background var(--primary) | ||||
| 				opacity 0 | ||||
| 				transform scaleX(0.12) | ||||
| 				transition border 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1), transform 0.3s cubic-bezier(0.4, 0, 0.2, 1) | ||||
| @@ -242,7 +236,7 @@ root(isDark, fill) | ||||
| 			transition-duration 0.3s | ||||
| 			font-size 16px | ||||
| 			line-height 32px | ||||
| 			color isDark ? rgba(#fff, 0.7) : rgba(#000, 0.54) | ||||
| 			color var(--inputLabel) | ||||
| 			pointer-events none | ||||
| 			//will-change transform | ||||
| 			transform-origin top left | ||||
| @@ -257,7 +251,7 @@ root(isDark, fill) | ||||
| 			font-weight fill ? bold : normal | ||||
| 			font-size 16px | ||||
| 			line-height 32px | ||||
| 			color isDark ? #fff : #000 | ||||
| 			color var(--inputText) | ||||
| 			background transparent | ||||
| 			border none | ||||
| 			border-radius 0 | ||||
| @@ -280,7 +274,7 @@ root(isDark, fill) | ||||
| 			top 0 | ||||
| 			font-size 16px | ||||
| 			line-height fill ? 44px : 32px | ||||
| 			color isDark ? rgba(#fff, 0.7) : rgba(#000, 0.54) | ||||
| 			color var(--inputLabel) | ||||
| 			pointer-events none | ||||
|  | ||||
| 			&:empty | ||||
| @@ -325,7 +319,7 @@ root(isDark, fill) | ||||
| 					transform scaleX(1) | ||||
|  | ||||
| 			> .label | ||||
| 				color $theme-color | ||||
| 				color var(--primary) | ||||
|  | ||||
| 	&.focused | ||||
| 	&.filled | ||||
| @@ -335,16 +329,10 @@ root(isDark, fill) | ||||
| 				left 0 !important | ||||
| 				transform scale(0.75) | ||||
|  | ||||
| .ui-input[data-darkmode] | ||||
| .ui-input | ||||
| 	&.fill | ||||
| 		root(true, true) | ||||
| 		root(true) | ||||
| 	&:not(.fill) | ||||
| 		root(true, false) | ||||
|  | ||||
| .ui-input:not([data-darkmode]) | ||||
| 	&.fill | ||||
| 		root(false, true) | ||||
| 	&:not(.fill) | ||||
| 		root(false, false) | ||||
| 		root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -51,9 +51,7 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
| .ui-radio | ||||
| 	display inline-block | ||||
| 	margin 0 32px 0 0 | ||||
| 	cursor pointer | ||||
| @@ -68,10 +66,10 @@ root(isDark) | ||||
|  | ||||
| 	&.checked | ||||
| 		> .button | ||||
| 			border-color $theme-color | ||||
| 			border-color var(--primary) | ||||
|  | ||||
| 			&:after | ||||
| 				background-color $theme-color | ||||
| 				background-color var(--primary) | ||||
| 				transform scale(1) | ||||
| 				opacity 1 | ||||
|  | ||||
| @@ -87,7 +85,7 @@ root(isDark) | ||||
| 		width 20px | ||||
| 		height 20px | ||||
| 		background none | ||||
| 		border solid 2px isDark ? rgba(#fff, 0.7) : rgba(#000, 0.54) | ||||
| 		border solid 2px var(--inputLabel) | ||||
| 		border-radius 100% | ||||
| 		transition inherit | ||||
|  | ||||
| @@ -111,10 +109,4 @@ root(isDark) | ||||
| 		line-height 20px | ||||
| 		cursor pointer | ||||
|  | ||||
| .ui-radio[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .ui-radio:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -29,13 +29,17 @@ export default Vue.extend({ | ||||
| 		required: { | ||||
| 			type: Boolean, | ||||
| 			required: false | ||||
| 		}, | ||||
| 		styl: { | ||||
| 			type: String, | ||||
| 			required: false, | ||||
| 			default: 'line' | ||||
| 		} | ||||
| 	}, | ||||
| 	data() { | ||||
| 		return { | ||||
| 			v: this.value, | ||||
| 			focused: false, | ||||
| 			styl: 'fill' | ||||
| 			focused: false | ||||
| 		}; | ||||
| 	}, | ||||
| 	computed: { | ||||
| @@ -48,14 +52,6 @@ export default Vue.extend({ | ||||
| 			this.v = v; | ||||
| 		} | ||||
| 	}, | ||||
| 	inject: { | ||||
| 		isCardChild: { default: false } | ||||
| 	}, | ||||
| 	created() { | ||||
| 		if (this.isCardChild) { | ||||
| 			this.styl = 'line'; | ||||
| 		} | ||||
| 	}, | ||||
| 	mounted() { | ||||
| 		if (this.$refs.prefix) { | ||||
| 			this.$refs.label.style.left = (this.$refs.prefix.offsetLeft + this.$refs.prefix.offsetWidth) + 'px'; | ||||
| @@ -70,9 +66,7 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark, fill) | ||||
| root(fill) | ||||
| 	margin 32px 0 | ||||
|  | ||||
| 	> .icon | ||||
| @@ -103,7 +97,7 @@ root(isDark, fill) | ||||
| 				left 0 | ||||
| 				right 0 | ||||
| 				height 1px | ||||
| 				background isDark ? rgba(#fff, 0.7) : rgba(#000, 0.42) | ||||
| 				background var(--inputBorder) | ||||
|  | ||||
| 			&:after | ||||
| 				content '' | ||||
| @@ -113,7 +107,7 @@ root(isDark, fill) | ||||
| 				left 0 | ||||
| 				right 0 | ||||
| 				height 2px | ||||
| 				background $theme-color | ||||
| 				background var(--primary) | ||||
| 				opacity 0 | ||||
| 				transform scaleX(0.12) | ||||
| 				transition border 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1), transform 0.3s cubic-bezier(0.4, 0, 0.2, 1) | ||||
| @@ -143,7 +137,7 @@ root(isDark, fill) | ||||
| 			font-weight fill ? bold : normal | ||||
| 			font-size 16px | ||||
| 			height 32px | ||||
| 			color isDark ? #fff : #000 | ||||
| 			color var(--inputText) | ||||
| 			background transparent | ||||
| 			border none | ||||
| 			border-radius 0 | ||||
| @@ -190,7 +184,7 @@ root(isDark, fill) | ||||
| 					transform scaleX(1) | ||||
|  | ||||
| 			> .label | ||||
| 				color $theme-color | ||||
| 				color var(--primary) | ||||
|  | ||||
| 	&.focused | ||||
| 	&.filled | ||||
| @@ -200,16 +194,10 @@ root(isDark, fill) | ||||
| 				left 0 !important | ||||
| 				transform scale(0.75) | ||||
|  | ||||
| .ui-select[data-darkmode] | ||||
| .ui-select | ||||
| 	&.fill | ||||
| 		root(true, true) | ||||
| 		root(true) | ||||
| 	&:not(.fill) | ||||
| 		root(true, false) | ||||
|  | ||||
| .ui-select:not([data-darkmode]) | ||||
| 	&.fill | ||||
| 		root(false, true) | ||||
| 	&:not(.fill) | ||||
| 		root(false, false) | ||||
| 		root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -19,7 +19,7 @@ | ||||
| 	<span class="label"> | ||||
| 		<span :aria-hidden="!checked"><slot></slot></span> | ||||
| 		<p :aria-hidden="!checked"> | ||||
| 			<slot name="text"></slot> | ||||
| 			<slot name="desc"></slot> | ||||
| 		</p> | ||||
| 	</span> | ||||
| </div> | ||||
| @@ -56,9 +56,7 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
| .ui-switch | ||||
| 	display flex | ||||
| 	margin 32px 0 | ||||
| 	cursor pointer | ||||
| @@ -79,11 +77,11 @@ root(isDark) | ||||
|  | ||||
| 	&.checked | ||||
| 		> .button | ||||
| 			background-color rgba($theme-color, 0.4) | ||||
| 			border-color rgba($theme-color, 0.4) | ||||
| 			background-color var(--primaryAlpha04) | ||||
| 			border-color var(--primaryAlpha04) | ||||
|  | ||||
| 			> * | ||||
| 				background-color $theme-color | ||||
| 				background-color var(--primary) | ||||
| 				transform translateX(14px) | ||||
|  | ||||
| 	> input | ||||
| @@ -99,7 +97,7 @@ root(isDark) | ||||
| 		margin 3px 0 0 0 | ||||
| 		width 34px | ||||
| 		height 14px | ||||
| 		background isDark ? rgba(#fff, 0.15) : rgba(#000, 0.25) | ||||
| 		background var(--switchTrack) | ||||
| 		outline none | ||||
| 		border-radius 14px | ||||
| 		transition inherit | ||||
| @@ -125,18 +123,11 @@ root(isDark) | ||||
| 		> span | ||||
| 			display block | ||||
| 			line-height 20px | ||||
| 			color isDark ? #c4ccd2 : rgba(#000, 0.75) | ||||
| 			color currentColor | ||||
| 			transition inherit | ||||
|  | ||||
| 		> p | ||||
| 			margin 0 | ||||
| 			//font-size 90% | ||||
| 			color isDark ? #78858e : #9daab3 | ||||
|  | ||||
| .ui-switch[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .ui-switch:not([data-darkmode]) | ||||
| 	root(false) | ||||
| 			opacity 0.7 | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -63,9 +63,7 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark, fill) | ||||
| root(fill) | ||||
| 	margin 42px 0 32px 0 | ||||
|  | ||||
| 	> .input | ||||
| @@ -84,7 +82,7 @@ root(isDark, fill) | ||||
| 				left 0 | ||||
| 				right 0 | ||||
| 				background none | ||||
| 				border solid 1px isDark ? rgba(#fff, 0.7) : rgba(#000, 0.42) | ||||
| 				border solid 1px var(--inputBorder) | ||||
| 				border-radius 3px | ||||
| 				pointer-events none | ||||
|  | ||||
| @@ -97,7 +95,7 @@ root(isDark, fill) | ||||
| 				left 0 | ||||
| 				right 0 | ||||
| 				background none | ||||
| 				border solid 2px $theme-color | ||||
| 				border solid 2px var(--primary) | ||||
| 				border-radius 3px | ||||
| 				opacity 0 | ||||
| 				transition opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1) | ||||
| @@ -112,7 +110,7 @@ root(isDark, fill) | ||||
| 			transition-duration 0.3s | ||||
| 			font-size 16px | ||||
| 			line-height 32px | ||||
| 			color isDark ? rgba(#fff, 0.7) : rgba(#000, 0.54) | ||||
| 			color var(--inputLabel) | ||||
| 			pointer-events none | ||||
| 			//will-change transform | ||||
| 			transform-origin top left | ||||
| @@ -126,7 +124,7 @@ root(isDark, fill) | ||||
| 			font inherit | ||||
| 			font-weight fill ? bold : normal | ||||
| 			font-size 16px | ||||
| 			color isDark ? #fff : #000 | ||||
| 			color var(--inputText) | ||||
| 			background transparent | ||||
| 			border none | ||||
| 			border-radius 0 | ||||
| @@ -149,7 +147,7 @@ root(isDark, fill) | ||||
| 					opacity 1 | ||||
|  | ||||
| 			> .label | ||||
| 				color $theme-color | ||||
| 				color var(--primary) | ||||
|  | ||||
| 	&.focused | ||||
| 	&.filled | ||||
| @@ -159,16 +157,10 @@ root(isDark, fill) | ||||
| 				left 0 !important | ||||
| 				transform scale(0.75) | ||||
|  | ||||
| .ui-textarea[data-darkmode] | ||||
| 	&.fill | ||||
| 		root(true, true) | ||||
| 	&:not(.fill) | ||||
| 		root(true, false) | ||||
| .ui-textarea.fill | ||||
| 	root(true) | ||||
|  | ||||
| .ui-textarea:not([data-darkmode]) | ||||
| 	&.fill | ||||
| 		root(false, true) | ||||
| 	&:not(.fill) | ||||
| 		root(false, false) | ||||
| .ui-textarea:not(.fill) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -20,6 +20,7 @@ | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import { apiUrl } from '../../../config'; | ||||
| import getMD5 from '../../scripts/get-md5'; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	data() { | ||||
| @@ -28,27 +29,48 @@ export default Vue.extend({ | ||||
| 		}; | ||||
| 	}, | ||||
| 	methods: { | ||||
| 		upload(file, folder) { | ||||
| 		checkExistence(fileData: ArrayBuffer): Promise<any> { | ||||
| 			return new Promise((resolve, reject) => { | ||||
| 				const data = new FormData(); | ||||
| 				data.append('md5', getMD5(fileData)); | ||||
|  | ||||
| 				(this as any).api('drive/files/check_existence', { | ||||
| 					md5: getMD5(fileData) | ||||
| 				}).then(resp => { | ||||
| 					resolve(resp.file); | ||||
| 				}); | ||||
| 			}); | ||||
| 		}, | ||||
|  | ||||
| 		upload(file: File, folder: any) { | ||||
| 			if (folder && typeof folder == 'object') folder = folder.id; | ||||
|  | ||||
| 			const id = Math.random(); | ||||
|  | ||||
| 			const reader = new FileReader(); | ||||
| 			reader.onload = (e: any) => { | ||||
| 				this.checkExistence(e.target.result).then(result => { | ||||
| 					if (result !== null) { | ||||
| 						this.$emit('uploaded', result); | ||||
| 						return; | ||||
| 					} | ||||
|  | ||||
| 					// Upload if the file didn't exist yet | ||||
| 					const buf = new Uint8Array(e.target.result); | ||||
| 					let bin = ''; | ||||
| 					// We use for-of loop instead of apply() to avoid RangeError | ||||
| 					// SEE: https://stackoverflow.com/questions/9267899/arraybuffer-to-base64-encoded-string | ||||
| 					for (const byte of buf) bin += String.fromCharCode(byte); | ||||
| 					const ctx = { | ||||
| 						id: id, | ||||
| 						name: file.name || 'untitled', | ||||
| 						progress: undefined, | ||||
| 				img: undefined | ||||
| 						img: 'data:*/*;base64,' + btoa(bin) | ||||
| 					}; | ||||
|  | ||||
| 					this.uploads.push(ctx); | ||||
| 					this.$emit('change', this.uploads); | ||||
|  | ||||
| 			const reader = new FileReader(); | ||||
| 			reader.onload = (e: any) => { | ||||
| 				ctx.img = e.target.result; | ||||
| 			}; | ||||
| 			reader.readAsDataURL(file); | ||||
|  | ||||
| 					const data = new FormData(); | ||||
| 					data.append('i', this.$store.state.i.token); | ||||
| 					data.append('file', file); | ||||
| @@ -75,14 +97,15 @@ export default Vue.extend({ | ||||
| 					}; | ||||
|  | ||||
| 					xhr.send(data); | ||||
| 				}) | ||||
| 			} | ||||
| 			reader.readAsArrayBuffer(file); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| .mk-uploader | ||||
| 	overflow auto | ||||
|  | ||||
| @@ -100,7 +123,7 @@ export default Vue.extend({ | ||||
| 			margin 8px 0 0 0 | ||||
| 			padding 0 | ||||
| 			height 36px | ||||
| 			box-shadow 0 -1px 0 rgba($theme-color, 0.1) | ||||
| 			box-shadow 0 -1px 0 var(--primaryAlpha01) | ||||
| 			border-top solid 8px transparent | ||||
|  | ||||
| 			&:first-child | ||||
| @@ -127,7 +150,7 @@ export default Vue.extend({ | ||||
| 				padding 0 | ||||
| 				max-width 256px | ||||
| 				font-size 0.8em | ||||
| 				color rgba($theme-color, 0.7) | ||||
| 				color var(--primaryAlpha07) | ||||
| 				white-space nowrap | ||||
| 				text-overflow ellipsis | ||||
| 				overflow hidden | ||||
| @@ -145,17 +168,17 @@ export default Vue.extend({ | ||||
| 				font-size 0.8em | ||||
|  | ||||
| 				> .initing | ||||
| 					color rgba($theme-color, 0.5) | ||||
| 					color var(--primaryAlpha05) | ||||
|  | ||||
| 				> .kb | ||||
| 					color rgba($theme-color, 0.5) | ||||
| 					color var(--primaryAlpha05) | ||||
|  | ||||
| 				> .percentage | ||||
| 					display inline-block | ||||
| 					width 48px | ||||
| 					text-align right | ||||
|  | ||||
| 					color rgba($theme-color, 0.7) | ||||
| 					color var(--primaryAlpha07) | ||||
|  | ||||
| 					&:after | ||||
| 						content '%' | ||||
| @@ -174,10 +197,10 @@ export default Vue.extend({ | ||||
| 				overflow hidden | ||||
|  | ||||
| 				&::-webkit-progress-value | ||||
| 					background $theme-color | ||||
| 					background var(--primary) | ||||
|  | ||||
| 				&::-webkit-progress-bar | ||||
| 					background rgba($theme-color, 0.1) | ||||
| 					background var(--primaryAlpha01) | ||||
|  | ||||
| 			> .progress | ||||
| 				display block | ||||
| @@ -191,13 +214,13 @@ export default Vue.extend({ | ||||
| 				border-radius 4px | ||||
| 				background linear-gradient( | ||||
| 					45deg, | ||||
| 					lighten($theme-color, 30%) 25%, | ||||
| 					$theme-color               25%, | ||||
| 					$theme-color               50%, | ||||
| 					lighten($theme-color, 30%) 50%, | ||||
| 					lighten($theme-color, 30%) 75%, | ||||
| 					$theme-color               75%, | ||||
| 					$theme-color | ||||
| 					var(--primaryLighten30) 25%, | ||||
| 					var(--primary)               25%, | ||||
| 					var(--primary)               50%, | ||||
| 					var(--primaryLighten30) 50%, | ||||
| 					var(--primaryLighten30) 75%, | ||||
| 					var(--primary)               75%, | ||||
| 					var(--primary) | ||||
| 				) | ||||
| 				background-size 32px 32px | ||||
| 				animation bg 1.5s linear infinite | ||||
|   | ||||
| @@ -200,17 +200,17 @@ export default Vue.extend({ | ||||
| 		top 0 | ||||
| 		width 100% | ||||
|  | ||||
| root(isDark) | ||||
| .mk-url-preview | ||||
| 	> a | ||||
| 		display block | ||||
| 		font-size 14px | ||||
| 		border solid 1px isDark ? #191b1f : #eee | ||||
| 		border solid 1px var(--urlPreviewBorder) | ||||
| 		border-radius 4px | ||||
| 		overflow hidden | ||||
|  | ||||
| 		&:hover | ||||
| 			text-decoration none | ||||
| 			border-color isDark ? #4f5561 : #ddd | ||||
| 			border-color var(--urlPreviewBorderHover) | ||||
|  | ||||
| 			> article > header > h1 | ||||
| 				text-decoration underline | ||||
| @@ -235,11 +235,11 @@ root(isDark) | ||||
| 				> h1 | ||||
| 					margin 0 | ||||
| 					font-size 1em | ||||
| 					color isDark ? #d6dae0 : #555 | ||||
| 					color var(--urlPreviewTitle) | ||||
|  | ||||
| 			> p | ||||
| 				margin 0 | ||||
| 				color isDark ? #a4aab3 : #777 | ||||
| 				color var(--urlPreviewText) | ||||
| 				font-size 0.8em | ||||
|  | ||||
| 			> footer | ||||
| @@ -256,7 +256,7 @@ root(isDark) | ||||
| 				> p | ||||
| 					display inline-block | ||||
| 					margin 0 | ||||
| 					color isDark ? #b0b4bf : #666 | ||||
| 					color var(--urlPreviewInfo) | ||||
| 					font-size 0.8em | ||||
| 					line-height 16px | ||||
| 					vertical-align top | ||||
| @@ -322,10 +322,4 @@ root(isDark) | ||||
| 						width 12px | ||||
| 						height 12px | ||||
|  | ||||
| .mk-url-preview[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .mk-url-preview:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -127,11 +127,9 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| $border-color = rgba(27, 31, 35, 0.15) | ||||
|  | ||||
| root(isDark) | ||||
| .mk-visibility-chooser | ||||
| 	position initial | ||||
|  | ||||
| 	> .backdrop | ||||
| @@ -141,11 +139,11 @@ root(isDark) | ||||
| 		z-index 10000 | ||||
| 		width 100% | ||||
| 		height 100% | ||||
| 		background isDark ? rgba(#000, 0.4) : rgba(#000, 0.1) | ||||
| 		background var(--modalBackdrop) | ||||
| 		opacity 0 | ||||
|  | ||||
| 	> .popover | ||||
| 		$bgcolor = isDark ? #2c303c : #fff | ||||
| 		$bgcolor = var(--popupBg) | ||||
| 		position absolute | ||||
| 		z-index 10001 | ||||
| 		width 240px | ||||
| @@ -189,18 +187,18 @@ root(isDark) | ||||
| 			display flex | ||||
| 			padding 8px 14px | ||||
| 			font-size 12px | ||||
| 			color isDark ? #fff : #666 | ||||
| 			color var(--popupFg) | ||||
| 			cursor pointer | ||||
|  | ||||
| 			&:hover | ||||
| 				background isDark ? #252731 : #eee | ||||
| 				background var(--faceClearButtonHover) | ||||
|  | ||||
| 			&:active | ||||
| 				background isDark ? #21242b : #ddd | ||||
| 				background var(--faceClearButtonActive) | ||||
|  | ||||
| 			&.active | ||||
| 				color $theme-color-foreground | ||||
| 				background $theme-color | ||||
| 				color var(--primaryForeground) | ||||
| 				background var(--primary) | ||||
|  | ||||
| 			> * | ||||
| 				user-select none | ||||
| @@ -222,11 +220,4 @@ root(isDark) | ||||
|  | ||||
| 				> span:last-child:not(:first-child) | ||||
| 					opacity 0.6 | ||||
|  | ||||
| .mk-visibility-chooser[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .mk-visibility-chooser:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -38,23 +38,20 @@ export default Vue.extend({ | ||||
| 		return { | ||||
| 			fetching: true, | ||||
| 			notes: [], | ||||
| 			connection: null, | ||||
| 			connectionId: null | ||||
| 			connection: null | ||||
| 		}; | ||||
| 	}, | ||||
|  | ||||
| 	mounted() { | ||||
| 		this.fetch(); | ||||
|  | ||||
| 		this.connection = (this as any).os.streams.localTimelineStream.getConnection(); | ||||
| 		this.connectionId = (this as any).os.streams.localTimelineStream.use(); | ||||
| 		this.connection = (this as any).os.stream.useSharedConnection('localTimeline'); | ||||
|  | ||||
| 		this.connection.on('note', this.onNote); | ||||
| 	}, | ||||
|  | ||||
| 	beforeDestroy() { | ||||
| 		this.connection.off('note', this.onNote); | ||||
| 		(this as any).os.streams.localTimelineStream.dispose(this.connectionId); | ||||
| 		this.connection.dispose(); | ||||
| 	}, | ||||
|  | ||||
| 	methods: { | ||||
| @@ -90,8 +87,8 @@ export default Vue.extend({ | ||||
| 	opacity 0 | ||||
| 	transform translateY(-30px) | ||||
|  | ||||
| root(isDark) | ||||
| 	background isDark ? #282C37 : #fff | ||||
| .mk-welcome-timeline | ||||
| 	background var(--face) | ||||
|  | ||||
| 	> div | ||||
| 		> * | ||||
| @@ -101,8 +98,8 @@ root(isDark) | ||||
| 			padding 16px | ||||
| 			overflow-wrap break-word | ||||
| 			font-size .9em | ||||
| 			color isDark ? #fff : #4C4C4C | ||||
| 			border-bottom 1px solid isDark ? rgba(#000, 0.1) : rgba(#000, 0.05) | ||||
| 			color var(--noteText) | ||||
| 			border-bottom 1px solid var(--faceDivider) | ||||
|  | ||||
| 			&:after | ||||
| 				content "" | ||||
| @@ -137,26 +134,20 @@ root(isDark) | ||||
| 						overflow hidden | ||||
| 						font-weight bold | ||||
| 						text-overflow ellipsis | ||||
| 						color isDark ? #fff : #627079 | ||||
| 						color var(--noteHeaderName) | ||||
|  | ||||
| 					> .username | ||||
| 						margin 0 .5em 0 0 | ||||
| 						color isDark ? #606984 : #ccc | ||||
| 						color var(--noteHeaderAcct) | ||||
|  | ||||
| 					> .info | ||||
| 						margin-left auto | ||||
| 						font-size 0.9em | ||||
|  | ||||
| 						> .created-at | ||||
| 							color isDark ? #606984 : #c0c0c0 | ||||
| 							color var(--noteHeaderInfo) | ||||
|  | ||||
| 				> .text | ||||
| 					text-align left | ||||
|  | ||||
| .mk-welcome-timeline[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .mk-welcome-timeline:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| <template> | ||||
| <div class="syxhndwprovvuqhmyvveewmbqayniwkv" v-if="!fetching" :data-darkmode="$store.state.device.darkmode"> | ||||
| <div class="syxhndwprovvuqhmyvveewmbqayniwkv" v-if="!fetching"> | ||||
| 	<div class="signed-in-as" v-html="'%i18n:@signed-in-as%'.replace('{}', `<b>${myName}`)"></div> | ||||
|  | ||||
| 	<main> | ||||
| @@ -19,7 +19,8 @@ | ||||
| 			@click="onClick" | ||||
| 			:disabled="followWait"> | ||||
| 		<template v-if="!followWait"> | ||||
| 			<template v-if="user.hasPendingFollowRequestFromYou">%fa:hourglass-half% %i18n:@request-pending%</template> | ||||
| 			<template v-if="user.hasPendingFollowRequestFromYou && user.isLocked">%fa:hourglass-half% %i18n:@request-pending%</template> | ||||
| 			<template v-else-if="user.hasPendingFollowRequestFromYou && !user.isLocked">%fa:hourglass-start% %i18n:@follow-processing%</template> | ||||
| 			<template v-else-if="user.isFollowing">%fa:minus% %i18n:@following%</template> | ||||
| 			<template v-else-if="!user.isFollowing && user.isLocked">%fa:plus% %i18n:@follow-request%</template> | ||||
| 			<template v-else-if="!user.isFollowing && !user.isLocked">%fa:plus% %i18n:@follow%</template> | ||||
| @@ -107,16 +108,14 @@ export default Vue.extend({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
| .syxhndwprovvuqhmyvveewmbqayniwkv | ||||
| 	padding 32px | ||||
| 	max-width 500px | ||||
| 	margin 0 auto | ||||
| 	text-align center | ||||
| 	color isDark ? #9baec8 : #868c8c | ||||
| 	color var(--text) | ||||
|  | ||||
| 	$bg = isDark ? #282C37 : #fff | ||||
| 	$bg = var(--face) | ||||
|  | ||||
| 	@media (max-width 400px) | ||||
| 		padding 16px | ||||
| @@ -124,7 +123,6 @@ root(isDark) | ||||
| 	> .signed-in-as | ||||
| 		margin-bottom 16px | ||||
| 		font-size 14px | ||||
| 		color isDark ? #9baec8 : #9daab3 | ||||
|  | ||||
| 	> main | ||||
| 		margin-bottom 16px | ||||
| @@ -173,29 +171,29 @@ root(isDark) | ||||
| 		min-width 150px | ||||
| 		font-size 14px | ||||
| 		font-weight bold | ||||
| 		color $theme-color | ||||
| 		color var(--primary) | ||||
| 		background transparent | ||||
| 		outline none | ||||
| 		border solid 1px $theme-color | ||||
| 		border solid 1px var(--primary) | ||||
| 		border-radius 36px | ||||
|  | ||||
| 		&:hover | ||||
| 			background rgba($theme-color, 0.1) | ||||
| 			background var(--primaryAlpha01) | ||||
|  | ||||
| 		&:active | ||||
| 			background rgba($theme-color, 0.2) | ||||
| 			background var(--primaryAlpha02) | ||||
|  | ||||
| 		&.active | ||||
| 			color $theme-color-foreground | ||||
| 			background $theme-color | ||||
| 			color var(--primaryForeground) | ||||
| 			background var(--primary) | ||||
|  | ||||
| 			&:hover | ||||
| 				background lighten($theme-color, 10%) | ||||
| 				border-color lighten($theme-color, 10%) | ||||
| 				background var(--primaryLighten10) | ||||
| 				border-color var(--primaryLighten10) | ||||
|  | ||||
| 			&:active | ||||
| 				background darken($theme-color, 10%) | ||||
| 				border-color darken($theme-color, 10%) | ||||
| 				background var(--primaryDarken10) | ||||
| 				border-color var(--primaryDarken10) | ||||
|  | ||||
| 		&.wait | ||||
| 			cursor wait !important | ||||
| @@ -204,10 +202,4 @@ root(isDark) | ||||
| 		* | ||||
| 			pointer-events none | ||||
|  | ||||
| .syxhndwprovvuqhmyvveewmbqayniwkv[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .syxhndwprovvuqhmyvveewmbqayniwkv:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -26,16 +26,8 @@ export default define({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
| .mkw-analog-clock | ||||
| 	.mkw-analog-clock--body | ||||
| 		padding 8px | ||||
|  | ||||
| .mkw-analog-clock[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .mkw-analog-clock:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -5,7 +5,6 @@ | ||||
| 			:data-found="announcements && announcements.length != 0" | ||||
| 			:data-melt="props.design == 1" | ||||
| 			:data-mobile="platform == 'mobile'" | ||||
| 			:data-darkmode="$store.state.device.darkmode" | ||||
| 		> | ||||
| 			<div class="icon"> | ||||
| 				<svg height="32" version="1.1" viewBox="0 0 32 32" width="32"> | ||||
| @@ -71,9 +70,9 @@ export default define({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| root(isDark) | ||||
| .anltbovirfeutcigvwgmgxipejaeozxi-body | ||||
| 	padding 10px | ||||
| 	background isDark ? #253a50 : #f3f9ff | ||||
| 	background var(--announcementsBg) | ||||
|  | ||||
| 	&[data-melt] | ||||
| 		background transparent | ||||
| @@ -130,14 +129,14 @@ root(isDark) | ||||
| 		margin 0 | ||||
| 		font-size 0.95em | ||||
| 		font-weight normal | ||||
| 		color isDark ? #539eff : #4078c0 | ||||
| 		color var(--announcementsTitle) | ||||
|  | ||||
| 	> p | ||||
| 		display block | ||||
| 		z-index 1 | ||||
| 		margin 0 | ||||
| 		font-size 0.7em | ||||
| 		color isDark ? #fff : #57616f | ||||
| 		color var(--announcementsText) | ||||
|  | ||||
| 		&.fetching | ||||
| 			text-align center | ||||
| @@ -150,10 +149,4 @@ root(isDark) | ||||
| 		> p | ||||
| 			color #fff | ||||
|  | ||||
| .anltbovirfeutcigvwgmgxipejaeozxi-body[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .anltbovirfeutcigvwgmgxipejaeozxi-body:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -116,15 +116,13 @@ export default define({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
| .mkw-calendar | ||||
| 	&[data-special='on-new-years-day'] | ||||
| 		border-color #ef95a0 | ||||
|  | ||||
| 	.mkw-calendar--body | ||||
| 		padding 16px 0 | ||||
| 		color isDark ? #c5ced6 : #777 | ||||
| 		color var(--calendarDay) | ||||
|  | ||||
| 		&:after | ||||
| 			content "" | ||||
| @@ -169,7 +167,8 @@ root(isDark) | ||||
| 					margin 0 0 2px 0 | ||||
| 					font-size 12px | ||||
| 					line-height 18px | ||||
| 					color isDark ? #7a8692 : #888 | ||||
| 					color var(--text) | ||||
| 					opacity 0.8 | ||||
|  | ||||
| 					> b | ||||
| 						margin-left 2px | ||||
| @@ -177,12 +176,12 @@ root(isDark) | ||||
| 				> .meter | ||||
| 					width 100% | ||||
| 					overflow hidden | ||||
| 					background isDark ? #1c1f25 : #eee | ||||
| 					background var(--materBg) | ||||
| 					border-radius 8px | ||||
|  | ||||
| 					> .val | ||||
| 						height 4px | ||||
| 						background $theme-color | ||||
| 						background var(--primary) | ||||
| 						transition width .3s cubic-bezier(0.23, 1, 0.32, 1) | ||||
|  | ||||
| 				&:nth-child(1) | ||||
| @@ -197,10 +196,4 @@ root(isDark) | ||||
| 					> .meter > .val | ||||
| 						background #41ddde | ||||
|  | ||||
| .mkw-calendar[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .mkw-calendar:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| <template> | ||||
| <div class="mkw-donation" :data-mobile="platform == 'mobile'"> | ||||
| 	<article> | ||||
| <div> | ||||
| 	<mk-widget-container :show-header="false"> | ||||
| 		<article class="dolfvtibguprpxxhfndqaosjitixjohx"> | ||||
| 			<h1>%fa:heart%%i18n:@title%</h1> | ||||
| 			<p v-if="meta"> | ||||
| 				{{ '%i18n:@text%'.substr(0, '%i18n:@text%'.indexOf('{')) }} | ||||
| @@ -8,6 +9,7 @@ | ||||
| 				{{ '%i18n:@text%'.substr('%i18n:@text%'.indexOf('}') + 1) }} | ||||
| 			</p> | ||||
| 		</article> | ||||
| 	</mk-widget-container> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
| @@ -30,18 +32,14 @@ export default define({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| root(isDark) | ||||
| 	background isDark ? #282c37 : #fff | ||||
| 	border solid 1px isDark ? #c3831c : #ead8bb | ||||
| 	border-radius 6px | ||||
|  | ||||
| 	> article | ||||
| .dolfvtibguprpxxhfndqaosjitixjohx | ||||
| 	padding 20px | ||||
| 	background var(--donationBg) | ||||
| 	color var(--donationFg) | ||||
|  | ||||
| 	> h1 | ||||
| 		margin 0 0 5px 0 | ||||
| 		font-size 1em | ||||
| 			color isDark ? #b2bac1 : #888 | ||||
|  | ||||
| 		> [data-fa] | ||||
| 			margin-right 0.25em | ||||
| @@ -51,25 +49,5 @@ root(isDark) | ||||
| 		z-index 1 | ||||
| 		margin 0 | ||||
| 		font-size 0.8em | ||||
| 			color isDark ? #a1a6ab : #999 | ||||
|  | ||||
| 	&[data-mobile] | ||||
| 		border none | ||||
| 		background #ead8bb | ||||
| 		border-radius 8px | ||||
| 		box-shadow 0 0 0 1px rgba(#000, 0.2) | ||||
|  | ||||
| 		> article | ||||
| 			> h1 | ||||
| 				color #7b8871 | ||||
|  | ||||
| 			> p | ||||
| 				color #777d71 | ||||
|  | ||||
| .mkw-donation[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .mkw-donation:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -57,9 +57,7 @@ export default define({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| @import '~const.styl' | ||||
|  | ||||
| root(isDark) | ||||
| .mkw-memo | ||||
| 	.mkw-memo--body | ||||
| 		padding-bottom 28px + 16px | ||||
|  | ||||
| @@ -69,10 +67,10 @@ root(isDark) | ||||
| 			max-width 100% | ||||
| 			min-width 100% | ||||
| 			padding 16px | ||||
| 			color isDark ? #fff : #222 | ||||
| 			background isDark ? #282c37 : #fff | ||||
| 			color var(--inputText) | ||||
| 			background var(--face) | ||||
| 			border none | ||||
| 			border-bottom solid 1px isDark ? #1c2023 : #eee | ||||
| 			border-bottom solid 1px var(--faceDivider) | ||||
| 			border-radius 0 | ||||
|  | ||||
| 		> button | ||||
| @@ -83,8 +81,8 @@ root(isDark) | ||||
| 			margin 0 | ||||
| 			padding 0 10px | ||||
| 			height 28px | ||||
| 			color $theme-color-foreground | ||||
| 			background $theme-color !important | ||||
| 			color var(--primaryForeground) | ||||
| 			background var(--primary) !important | ||||
| 			outline none | ||||
| 			border none | ||||
| 			border-radius 4px | ||||
| @@ -92,20 +90,14 @@ root(isDark) | ||||
| 			cursor pointer | ||||
|  | ||||
| 			&:hover | ||||
| 				background lighten($theme-color, 10%) !important | ||||
| 				background var(--primaryLighten10) !important | ||||
|  | ||||
| 			&:active | ||||
| 				background darken($theme-color, 10%) !important | ||||
| 				background var(--primaryDarken10) !important | ||||
| 				transition background 0s ease | ||||
|  | ||||
| 			&:disabled | ||||
| 				opacity 0.7 | ||||
| 				cursor default | ||||
|  | ||||
| .mkw-memo[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .mkw-memo:not([data-darkmode]) | ||||
| 	root(false) | ||||
|  | ||||
| </style> | ||||
|   | ||||
| @@ -16,23 +16,17 @@ export default define({ | ||||
| </script> | ||||
|  | ||||
| <style lang="stylus" scoped> | ||||
| root(isDark) | ||||
| .mkw-nav | ||||
| 	.mkw-nav--body | ||||
| 		padding 16px | ||||
| 		font-size 12px | ||||
| 		color isDark ? #9aa4b3 : #aaa | ||||
| 		background isDark ? #282c37 : #fff | ||||
| 		color var(--text) | ||||
| 		background var(--face) | ||||
|  | ||||
| 		a | ||||
| 			color isDark ? #9aa4b3 : #999 | ||||
| 			color var(--text) | ||||
|  | ||||
| 		i | ||||
| 			color isDark ? #9aa4b3 : #ccc | ||||
|  | ||||
| .mkw-nav[data-darkmode] | ||||
| 	root(true) | ||||
|  | ||||
| .mkw-nav:not([data-darkmode]) | ||||
| 	root(false) | ||||
| 			color var(--text) | ||||
|  | ||||
| </style> | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user