Compare commits
	
		
			37 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					5f33713f53 | ||
| 
						 | 
					fe84c5010c | ||
| 
						 | 
					7f39df0713 | ||
| 
						 | 
					928d359dd2 | ||
| 
						 | 
					184eb00133 | ||
| 
						 | 
					e264a49b08 | ||
| 
						 | 
					8caf853c80 | ||
| 
						 | 
					b451c04787 | ||
| 
						 | 
					1653977392 | ||
| 
						 | 
					a0d9def98a | ||
| 
						 | 
					92701e5cec | ||
| 
						 | 
					0b6b6a4f2f | ||
| 
						 | 
					3a2dc95850 | ||
| 
						 | 
					163cf49f16 | ||
| 
						 | 
					37fc3103f6 | ||
| 
						 | 
					b7bd1ff69f | ||
| 
						 | 
					dc36134f10 | ||
| 
						 | 
					fea8821091 | ||
| 
						 | 
					33faf40aca | ||
| 
						 | 
					4410f8d7f7 | ||
| 
						 | 
					3e6029e69d | ||
| 
						 | 
					96c7707e6c | ||
| 
						 | 
					d8e545db3c | ||
| 
						 | 
					a9a6ba0aed | ||
| 
						 | 
					a898c6ceab | ||
| 
						 | 
					0205c5c2d7 | ||
| 
						 | 
					f8074ab74b | ||
| 
						 | 
					f15c491d5f | ||
| 
						 | 
					c38a32dee9 | ||
| 
						 | 
					4f5abed70d | ||
| 
						 | 
					c9ac9923df | ||
| 
						 | 
					bb14895fd8 | ||
| 
						 | 
					6f92d601ec | ||
| 
						 | 
					345143b0c1 | ||
| 
						 | 
					381f2b7fdf | ||
| 
						 | 
					1c3c733c6b | ||
| 
						 | 
					9dbc9115c9 | 
@@ -1434,6 +1434,9 @@ mobile/views/pages/user.vue:
 | 
				
			|||||||
  block: "ブロック"
 | 
					  block: "ブロック"
 | 
				
			||||||
  unblock: "ブロック解除"
 | 
					  unblock: "ブロック解除"
 | 
				
			||||||
  years-old: "{age}歳"
 | 
					  years-old: "{age}歳"
 | 
				
			||||||
 | 
					  push-to-list: "リストに追加"
 | 
				
			||||||
 | 
					  select-list: "リストを選択してください"
 | 
				
			||||||
 | 
					  list-pushed: "{user}を{list}に追加しました"
 | 
				
			||||||
mobile/views/pages/user/home.vue:
 | 
					mobile/views/pages/user/home.vue:
 | 
				
			||||||
  recent-notes: "最近の投稿"
 | 
					  recent-notes: "最近の投稿"
 | 
				
			||||||
  images: "画像"
 | 
					  images: "画像"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1434,6 +1434,9 @@ mobile/views/pages/user.vue:
 | 
				
			|||||||
  block: "ブロック"
 | 
					  block: "ブロック"
 | 
				
			||||||
  unblock: "ブロック解除"
 | 
					  unblock: "ブロック解除"
 | 
				
			||||||
  years-old: "{age}歳"
 | 
					  years-old: "{age}歳"
 | 
				
			||||||
 | 
					  push-to-list: "リストに追加"
 | 
				
			||||||
 | 
					  select-list: "リストを選択してください"
 | 
				
			||||||
 | 
					  list-pushed: "{user}を{list}に追加しました"
 | 
				
			||||||
mobile/views/pages/user/home.vue:
 | 
					mobile/views/pages/user/home.vue:
 | 
				
			||||||
  recent-notes: "最近の投稿"
 | 
					  recent-notes: "最近の投稿"
 | 
				
			||||||
  images: "画像"
 | 
					  images: "画像"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,7 +26,7 @@ common:
 | 
				
			|||||||
  close: "Close"
 | 
					  close: "Close"
 | 
				
			||||||
  do-not-copy-paste: "Please do not enter or paste the code here. Account may be compromised."
 | 
					  do-not-copy-paste: "Please do not enter or paste the code here. Account may be compromised."
 | 
				
			||||||
  load-more: "Load more"
 | 
					  load-more: "Load more"
 | 
				
			||||||
  enter-password: "パスワードを入力してください"
 | 
					  enter-password: "Please enter the Password"
 | 
				
			||||||
  got-it: "Got it!"
 | 
					  got-it: "Got it!"
 | 
				
			||||||
  customization-tips:
 | 
					  customization-tips:
 | 
				
			||||||
    title: "Customization tips"
 | 
					    title: "Customization tips"
 | 
				
			||||||
@@ -1008,8 +1008,8 @@ admin/views/instance.vue:
 | 
				
			|||||||
  email-config-info: "Used to confirm email and password reset etc."
 | 
					  email-config-info: "Used to confirm email and password reset etc."
 | 
				
			||||||
  enable-email: "Enable email delivery"
 | 
					  enable-email: "Enable email delivery"
 | 
				
			||||||
  email: "Email Address"
 | 
					  email: "Email Address"
 | 
				
			||||||
  smtp-secure: "SMTP接続に暗黙的なSSL/TLSを使用する"
 | 
					  smtp-secure: "Use implicit SSL/TLS in the SMTP connection"
 | 
				
			||||||
  smtp-secure-info: "STARTTLS使用時はオフにします。"
 | 
					  smtp-secure-info: "Turn off STARTTLS when used that."
 | 
				
			||||||
  smtp-host: "SMTP Host"
 | 
					  smtp-host: "SMTP Host"
 | 
				
			||||||
  smtp-port: "SMTP Port"
 | 
					  smtp-port: "SMTP Port"
 | 
				
			||||||
  smtp-user: "SMTP User"
 | 
					  smtp-user: "SMTP User"
 | 
				
			||||||
@@ -1434,6 +1434,9 @@ mobile/views/pages/user.vue:
 | 
				
			|||||||
  block: "Block"
 | 
					  block: "Block"
 | 
				
			||||||
  unblock: "Unblock"
 | 
					  unblock: "Unblock"
 | 
				
			||||||
  years-old: "{age} years old"
 | 
					  years-old: "{age} years old"
 | 
				
			||||||
 | 
					  push-to-list: "Add to list"
 | 
				
			||||||
 | 
					  select-list: "Select a list"
 | 
				
			||||||
 | 
					  list-pushed: "Successfully added {user} to {list}."
 | 
				
			||||||
mobile/views/pages/user/home.vue:
 | 
					mobile/views/pages/user/home.vue:
 | 
				
			||||||
  recent-notes: "Recent notes"
 | 
					  recent-notes: "Recent notes"
 | 
				
			||||||
  images: "Images"
 | 
					  images: "Images"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1434,6 +1434,9 @@ mobile/views/pages/user.vue:
 | 
				
			|||||||
  block: "ブロック"
 | 
					  block: "ブロック"
 | 
				
			||||||
  unblock: "ブロック解除"
 | 
					  unblock: "ブロック解除"
 | 
				
			||||||
  years-old: "{age}歳"
 | 
					  years-old: "{age}歳"
 | 
				
			||||||
 | 
					  push-to-list: "リストに追加"
 | 
				
			||||||
 | 
					  select-list: "リストを選択してください"
 | 
				
			||||||
 | 
					  list-pushed: "{user}を{list}に追加しました"
 | 
				
			||||||
mobile/views/pages/user/home.vue:
 | 
					mobile/views/pages/user/home.vue:
 | 
				
			||||||
  recent-notes: "最近の投稿"
 | 
					  recent-notes: "最近の投稿"
 | 
				
			||||||
  images: "画像"
 | 
					  images: "画像"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,7 +26,7 @@ common:
 | 
				
			|||||||
  close: "Fermer"
 | 
					  close: "Fermer"
 | 
				
			||||||
  do-not-copy-paste: "Veuillez ne pas entrer ou coller le code ici. Le compte peut être compromis."
 | 
					  do-not-copy-paste: "Veuillez ne pas entrer ou coller le code ici. Le compte peut être compromis."
 | 
				
			||||||
  load-more: "Charger plus"
 | 
					  load-more: "Charger plus"
 | 
				
			||||||
  enter-password: "パスワードを入力してください"
 | 
					  enter-password: "Veuillez entrer le mot de passe"
 | 
				
			||||||
  got-it: "J’ai compris !"
 | 
					  got-it: "J’ai compris !"
 | 
				
			||||||
  customization-tips:
 | 
					  customization-tips:
 | 
				
			||||||
    title: "Conseils de personnalisation"
 | 
					    title: "Conseils de personnalisation"
 | 
				
			||||||
@@ -458,10 +458,10 @@ common/views/components/profile-editor.vue:
 | 
				
			|||||||
  saved: "Profil mis à jour avec succès"
 | 
					  saved: "Profil mis à jour avec succès"
 | 
				
			||||||
  uploading: "En cours d'envoi …"
 | 
					  uploading: "En cours d'envoi …"
 | 
				
			||||||
  upload-failed: "Échec de l'envoi"
 | 
					  upload-failed: "Échec de l'envoi"
 | 
				
			||||||
  email: "メール設定"
 | 
					  email: "Paramètres de messagerie"
 | 
				
			||||||
  email-address: "メールアドレス"
 | 
					  email-address: "Adresse de courrier électronique"
 | 
				
			||||||
  email-verified: "メールアドレスが確認されました"
 | 
					  email-verified: "L’adresse du courrier électronique a été vérifiée."
 | 
				
			||||||
  email-not-verified: "メールアドレスが確認されていません。メールボックスをご確認ください。"
 | 
					  email-not-verified: "Adresse de courriel n’est pas confirmée. Veuillez vérifier votre boite de réception."
 | 
				
			||||||
common/views/widgets/broadcast.vue:
 | 
					common/views/widgets/broadcast.vue:
 | 
				
			||||||
  fetching: "Récupération"
 | 
					  fetching: "Récupération"
 | 
				
			||||||
  no-broadcasts: "Aucune annonce"
 | 
					  no-broadcasts: "Aucune annonce"
 | 
				
			||||||
@@ -736,8 +736,8 @@ desktop/views/components/settings.vue:
 | 
				
			|||||||
  note-visibility: "Visibilité de la publication"
 | 
					  note-visibility: "Visibilité de la publication"
 | 
				
			||||||
  default-note-visibility: "Visibilité par défaut"
 | 
					  default-note-visibility: "Visibilité par défaut"
 | 
				
			||||||
  remember-note-visibility: "Se souvenir du mode de visibilité de la publication"
 | 
					  remember-note-visibility: "Se souvenir du mode de visibilité de la publication"
 | 
				
			||||||
  web-search-engine: "ウェブ検索エンジン"
 | 
					  web-search-engine: "Moteur de recherche Web"
 | 
				
			||||||
  web-search-engine-desc: "例: https://www.google.com/?#q={{query}}"
 | 
					  web-search-engine-desc: "Exemple : https://www.google.com/?#q={{query}}"
 | 
				
			||||||
  auto-popout: "Fenêtre contextuelle automatique"
 | 
					  auto-popout: "Fenêtre contextuelle automatique"
 | 
				
			||||||
  auto-popout-desc: "ウィンドウが開かれるとき、ポップアウト(ブラウザ外に切り離す)可能なら自動でポップアウトします。この設定はブラウザに記憶されます。"
 | 
					  auto-popout-desc: "ウィンドウが開かれるとき、ポップアウト(ブラウザ外に切り離す)可能なら自動でポップアウトします。この設定はブラウザに記憶されます。"
 | 
				
			||||||
  advanced: "Paramètres avancés"
 | 
					  advanced: "Paramètres avancés"
 | 
				
			||||||
@@ -1004,16 +1004,16 @@ admin/views/instance.vue:
 | 
				
			|||||||
  external-user-recommendation-engine-desc: "Exemple : https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
 | 
					  external-user-recommendation-engine-desc: "Exemple : https://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-misskey-api.cgi?{{host}}+{{user}}+{{limit}}+{{offset}}"
 | 
				
			||||||
  external-user-recommendation-timeout: "Délai d’expiration"
 | 
					  external-user-recommendation-timeout: "Délai d’expiration"
 | 
				
			||||||
  external-user-recommendation-timeout-desc: "En millisecondes (par exemple : 300000)"
 | 
					  external-user-recommendation-timeout-desc: "En millisecondes (par exemple : 300000)"
 | 
				
			||||||
  email-config: "メールサーバーの設定"
 | 
					  email-config: "Paramètres du serveur de messagerie"
 | 
				
			||||||
  email-config-info: "メールアドレス確認やパスワードリセットの際に使われます。"
 | 
					  email-config-info: "Utilisé pour confirmer votre adresse de courrier électronique et la réinitialisation de votre mot de passe."
 | 
				
			||||||
  enable-email: "メール配信を有効にする"
 | 
					  enable-email: "Activation de la distribution du courrier"
 | 
				
			||||||
  email: "メールアドレス"
 | 
					  email: "Adresse de courrier électronique"
 | 
				
			||||||
  smtp-secure: "SMTP接続に暗黙的なSSL/TLSを使用する"
 | 
					  smtp-secure: "Utiliser SSL/TLS implicitement dans la connexion SMTP"
 | 
				
			||||||
  smtp-secure-info: "STARTTLS使用時はオフにします。"
 | 
					  smtp-secure-info: "Désactiver STARTTLS lorsque celui-ci est utilisé."
 | 
				
			||||||
  smtp-host: "SMTPホスト"
 | 
					  smtp-host: "Hôte SMTP"
 | 
				
			||||||
  smtp-port: "SMTPポート"
 | 
					  smtp-port: "Port SMTP"
 | 
				
			||||||
  smtp-user: "SMTPユーザー"
 | 
					  smtp-user: "Utilisateur SMTP"
 | 
				
			||||||
  smtp-pass: "SMTPパスワード"
 | 
					  smtp-pass: "Mot de passe SMTP"
 | 
				
			||||||
admin/views/charts.vue:
 | 
					admin/views/charts.vue:
 | 
				
			||||||
  title: "Graph"
 | 
					  title: "Graph"
 | 
				
			||||||
  per-day: "par jour"
 | 
					  per-day: "par jour"
 | 
				
			||||||
@@ -1388,8 +1388,8 @@ mobile/views/pages/settings.vue:
 | 
				
			|||||||
  note-visibility: "Visibilité de la publication"
 | 
					  note-visibility: "Visibilité de la publication"
 | 
				
			||||||
  default-note-visibility: "Visibilité par défaut"
 | 
					  default-note-visibility: "Visibilité par défaut"
 | 
				
			||||||
  remember-note-visibility: "Se souvenir du mode de visibilité de la publication"
 | 
					  remember-note-visibility: "Se souvenir du mode de visibilité de la publication"
 | 
				
			||||||
  web-search-engine: "ウェブ検索エンジン"
 | 
					  web-search-engine: "Moteur de recherche Web"
 | 
				
			||||||
  web-search-engine-desc: "例: https://www.google.com/?#q={{query}}"
 | 
					  web-search-engine-desc: "Exemple : https://www.google.com/?#q={{query}}"
 | 
				
			||||||
  disable-via-mobile: "Ne pas mentionner que ma publication provient d'un 'périphérique mobile'"
 | 
					  disable-via-mobile: "Ne pas mentionner que ma publication provient d'un 'périphérique mobile'"
 | 
				
			||||||
  load-raw-images: "Afficher les photos jointes en haute qualité"
 | 
					  load-raw-images: "Afficher les photos jointes en haute qualité"
 | 
				
			||||||
  load-remote-media: "Afficher les médias sur le serveur distant"
 | 
					  load-remote-media: "Afficher les médias sur le serveur distant"
 | 
				
			||||||
@@ -1434,6 +1434,9 @@ mobile/views/pages/user.vue:
 | 
				
			|||||||
  block: "Bloquer"
 | 
					  block: "Bloquer"
 | 
				
			||||||
  unblock: "Débloquer"
 | 
					  unblock: "Débloquer"
 | 
				
			||||||
  years-old: "{age} ans"
 | 
					  years-old: "{age} ans"
 | 
				
			||||||
 | 
					  push-to-list: "リストに追加"
 | 
				
			||||||
 | 
					  select-list: "リストを選択してください"
 | 
				
			||||||
 | 
					  list-pushed: "{user}を{list}に追加しました"
 | 
				
			||||||
mobile/views/pages/user/home.vue:
 | 
					mobile/views/pages/user/home.vue:
 | 
				
			||||||
  recent-notes: "Notes récentes"
 | 
					  recent-notes: "Notes récentes"
 | 
				
			||||||
  images: "Images"
 | 
					  images: "Images"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1434,6 +1434,9 @@ mobile/views/pages/user.vue:
 | 
				
			|||||||
  block: "ブロック"
 | 
					  block: "ブロック"
 | 
				
			||||||
  unblock: "ブロック解除"
 | 
					  unblock: "ブロック解除"
 | 
				
			||||||
  years-old: "{age}歳"
 | 
					  years-old: "{age}歳"
 | 
				
			||||||
 | 
					  push-to-list: "リストに追加"
 | 
				
			||||||
 | 
					  select-list: "リストを選択してください"
 | 
				
			||||||
 | 
					  list-pushed: "{user}を{list}に追加しました"
 | 
				
			||||||
mobile/views/pages/user/home.vue:
 | 
					mobile/views/pages/user/home.vue:
 | 
				
			||||||
  recent-notes: "最近の投稿"
 | 
					  recent-notes: "最近の投稿"
 | 
				
			||||||
  images: "画像"
 | 
					  images: "画像"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1628,6 +1628,9 @@ mobile/views/pages/user.vue:
 | 
				
			|||||||
  block: "ブロック"
 | 
					  block: "ブロック"
 | 
				
			||||||
  unblock: "ブロック解除"
 | 
					  unblock: "ブロック解除"
 | 
				
			||||||
  years-old: "{age}歳"
 | 
					  years-old: "{age}歳"
 | 
				
			||||||
 | 
					  push-to-list: "リストに追加"
 | 
				
			||||||
 | 
					  select-list: "リストを選択してください"
 | 
				
			||||||
 | 
					  list-pushed: "{user}を{list}に追加しました"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mobile/views/pages/user/home.vue:
 | 
					mobile/views/pages/user/home.vue:
 | 
				
			||||||
  recent-notes: "最近の投稿"
 | 
					  recent-notes: "最近の投稿"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1434,6 +1434,9 @@ mobile/views/pages/user.vue:
 | 
				
			|||||||
  block: "ブロック"
 | 
					  block: "ブロック"
 | 
				
			||||||
  unblock: "ブロックやめたる"
 | 
					  unblock: "ブロックやめたる"
 | 
				
			||||||
  years-old: "{age}歳"
 | 
					  years-old: "{age}歳"
 | 
				
			||||||
 | 
					  push-to-list: "リストに追加"
 | 
				
			||||||
 | 
					  select-list: "リストを選択してください"
 | 
				
			||||||
 | 
					  list-pushed: "{user}を{list}に追加しました"
 | 
				
			||||||
mobile/views/pages/user/home.vue:
 | 
					mobile/views/pages/user/home.vue:
 | 
				
			||||||
  recent-notes: "最近儲かりまっか?"
 | 
					  recent-notes: "最近儲かりまっか?"
 | 
				
			||||||
  images: "画像"
 | 
					  images: "画像"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1434,6 +1434,9 @@ mobile/views/pages/user.vue:
 | 
				
			|||||||
  block: "차단"
 | 
					  block: "차단"
 | 
				
			||||||
  unblock: "차단 해제"
 | 
					  unblock: "차단 해제"
 | 
				
			||||||
  years-old: "{age}세"
 | 
					  years-old: "{age}세"
 | 
				
			||||||
 | 
					  push-to-list: "リストに追加"
 | 
				
			||||||
 | 
					  select-list: "リストを選択してください"
 | 
				
			||||||
 | 
					  list-pushed: "{user}を{list}に追加しました"
 | 
				
			||||||
mobile/views/pages/user/home.vue:
 | 
					mobile/views/pages/user/home.vue:
 | 
				
			||||||
  recent-notes: "최근 글"
 | 
					  recent-notes: "최근 글"
 | 
				
			||||||
  images: "이미지"
 | 
					  images: "이미지"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1434,6 +1434,9 @@ mobile/views/pages/user.vue:
 | 
				
			|||||||
  block: "ブロック"
 | 
					  block: "ブロック"
 | 
				
			||||||
  unblock: "ブロック解除"
 | 
					  unblock: "ブロック解除"
 | 
				
			||||||
  years-old: "{age}歳"
 | 
					  years-old: "{age}歳"
 | 
				
			||||||
 | 
					  push-to-list: "リストに追加"
 | 
				
			||||||
 | 
					  select-list: "リストを選択してください"
 | 
				
			||||||
 | 
					  list-pushed: "{user}を{list}に追加しました"
 | 
				
			||||||
mobile/views/pages/user/home.vue:
 | 
					mobile/views/pages/user/home.vue:
 | 
				
			||||||
  recent-notes: "Recente notities"
 | 
					  recent-notes: "Recente notities"
 | 
				
			||||||
  images: "Afbeeldingen"
 | 
					  images: "Afbeeldingen"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1434,6 +1434,9 @@ mobile/views/pages/user.vue:
 | 
				
			|||||||
  block: "ブロック"
 | 
					  block: "ブロック"
 | 
				
			||||||
  unblock: "ブロック解除"
 | 
					  unblock: "ブロック解除"
 | 
				
			||||||
  years-old: "{age}歳"
 | 
					  years-old: "{age}歳"
 | 
				
			||||||
 | 
					  push-to-list: "リストに追加"
 | 
				
			||||||
 | 
					  select-list: "リストを選択してください"
 | 
				
			||||||
 | 
					  list-pushed: "{user}を{list}に追加しました"
 | 
				
			||||||
mobile/views/pages/user/home.vue:
 | 
					mobile/views/pages/user/home.vue:
 | 
				
			||||||
  recent-notes: "Nylige innlegg"
 | 
					  recent-notes: "Nylige innlegg"
 | 
				
			||||||
  images: "Bilder"
 | 
					  images: "Bilder"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1434,6 +1434,9 @@ mobile/views/pages/user.vue:
 | 
				
			|||||||
  block: "ブロック"
 | 
					  block: "ブロック"
 | 
				
			||||||
  unblock: "ブロック解除"
 | 
					  unblock: "ブロック解除"
 | 
				
			||||||
  years-old: "{age} lat"
 | 
					  years-old: "{age} lat"
 | 
				
			||||||
 | 
					  push-to-list: "リストに追加"
 | 
				
			||||||
 | 
					  select-list: "リストを選択してください"
 | 
				
			||||||
 | 
					  list-pushed: "{user}を{list}に追加しました"
 | 
				
			||||||
mobile/views/pages/user/home.vue:
 | 
					mobile/views/pages/user/home.vue:
 | 
				
			||||||
  recent-notes: "Ostatnie wpisy"
 | 
					  recent-notes: "Ostatnie wpisy"
 | 
				
			||||||
  images: "Zdjęcia"
 | 
					  images: "Zdjęcia"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1434,6 +1434,9 @@ mobile/views/pages/user.vue:
 | 
				
			|||||||
  block: "ブロック"
 | 
					  block: "ブロック"
 | 
				
			||||||
  unblock: "ブロック解除"
 | 
					  unblock: "ブロック解除"
 | 
				
			||||||
  years-old: "{age}歳"
 | 
					  years-old: "{age}歳"
 | 
				
			||||||
 | 
					  push-to-list: "リストに追加"
 | 
				
			||||||
 | 
					  select-list: "リストを選択してください"
 | 
				
			||||||
 | 
					  list-pushed: "{user}を{list}に追加しました"
 | 
				
			||||||
mobile/views/pages/user/home.vue:
 | 
					mobile/views/pages/user/home.vue:
 | 
				
			||||||
  recent-notes: "Notas recentes"
 | 
					  recent-notes: "Notas recentes"
 | 
				
			||||||
  images: "Imagens"
 | 
					  images: "Imagens"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1434,6 +1434,9 @@ mobile/views/pages/user.vue:
 | 
				
			|||||||
  block: "ブロック"
 | 
					  block: "ブロック"
 | 
				
			||||||
  unblock: "ブロック解除"
 | 
					  unblock: "ブロック解除"
 | 
				
			||||||
  years-old: "{age}歳"
 | 
					  years-old: "{age}歳"
 | 
				
			||||||
 | 
					  push-to-list: "リストに追加"
 | 
				
			||||||
 | 
					  select-list: "リストを選択してください"
 | 
				
			||||||
 | 
					  list-pushed: "{user}を{list}に追加しました"
 | 
				
			||||||
mobile/views/pages/user/home.vue:
 | 
					mobile/views/pages/user/home.vue:
 | 
				
			||||||
  recent-notes: "最近の投稿"
 | 
					  recent-notes: "最近の投稿"
 | 
				
			||||||
  images: "画像"
 | 
					  images: "画像"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1434,6 +1434,9 @@ mobile/views/pages/user.vue:
 | 
				
			|||||||
  block: "屏蔽"
 | 
					  block: "屏蔽"
 | 
				
			||||||
  unblock: "取消屏蔽"
 | 
					  unblock: "取消屏蔽"
 | 
				
			||||||
  years-old: "{age}岁"
 | 
					  years-old: "{age}岁"
 | 
				
			||||||
 | 
					  push-to-list: "リストに追加"
 | 
				
			||||||
 | 
					  select-list: "リストを選択してください"
 | 
				
			||||||
 | 
					  list-pushed: "{user}を{list}に追加しました"
 | 
				
			||||||
mobile/views/pages/user/home.vue:
 | 
					mobile/views/pages/user/home.vue:
 | 
				
			||||||
  recent-notes: "最近的帖子"
 | 
					  recent-notes: "最近的帖子"
 | 
				
			||||||
  images: "图片"
 | 
					  images: "图片"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	"name": "misskey",
 | 
						"name": "misskey",
 | 
				
			||||||
	"author": "syuilo <i@syuilo.com>",
 | 
						"author": "syuilo <i@syuilo.com>",
 | 
				
			||||||
	"version": "10.59.4",
 | 
						"version": "10.60.1",
 | 
				
			||||||
	"clientVersion": "2.0.12323",
 | 
						"clientVersion": "2.0.12361",
 | 
				
			||||||
	"codename": "nighthike",
 | 
						"codename": "nighthike",
 | 
				
			||||||
	"main": "./built/index.js",
 | 
						"main": "./built/index.js",
 | 
				
			||||||
	"private": true,
 | 
						"private": true,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,15 +48,15 @@ export default Vue.extend({
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		remove(i) {
 | 
							remove(i) {
 | 
				
			||||||
			this.$root.alert({
 | 
								this.$root.dialog({
 | 
				
			||||||
				type: 'warning',
 | 
									type: 'warning',
 | 
				
			||||||
				text: this.$t('_remove.are-you-sure').replace('$1', this.announcements.find((_, j) => j == i).title),
 | 
									text: this.$t('_remove.are-you-sure').replace('$1', this.announcements.find((_, j) => j == i).title),
 | 
				
			||||||
				showCancelButton: true
 | 
									showCancelButton: true
 | 
				
			||||||
			}).then(res => {
 | 
								}).then(({ canceled }) => {
 | 
				
			||||||
				if (!res) return;
 | 
									if (canceled) return;
 | 
				
			||||||
				this.announcements = this.announcements.filter((_, j) => j !== i);
 | 
									this.announcements = this.announcements.filter((_, j) => j !== i);
 | 
				
			||||||
				this.save(true);
 | 
									this.save(true);
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'success',
 | 
										type: 'success',
 | 
				
			||||||
					text: this.$t('_remove.removed')
 | 
										text: this.$t('_remove.removed')
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
@@ -68,13 +68,13 @@ export default Vue.extend({
 | 
				
			|||||||
				broadcasts: this.announcements
 | 
									broadcasts: this.announcements
 | 
				
			||||||
			}).then(() => {
 | 
								}).then(() => {
 | 
				
			||||||
				if (!silent) {
 | 
									if (!silent) {
 | 
				
			||||||
					this.$root.alert({
 | 
										this.$root.dialog({
 | 
				
			||||||
						type: 'success',
 | 
											type: 'success',
 | 
				
			||||||
						text: this.$t('saved')
 | 
											text: this.$t('saved')
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}).catch(e => {
 | 
								}).catch(e => {
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'error',
 | 
										type: 'error',
 | 
				
			||||||
					text: e
 | 
										text: e
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -75,13 +75,13 @@ export default Vue.extend({
 | 
				
			|||||||
				url: this.url,
 | 
									url: this.url,
 | 
				
			||||||
				aliases: this.aliases.split(' ').filter(x => x.length > 0)
 | 
									aliases: this.aliases.split(' ').filter(x => x.length > 0)
 | 
				
			||||||
			}).then(() => {
 | 
								}).then(() => {
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'success',
 | 
										type: 'success',
 | 
				
			||||||
					text: this.$t('add-emoji.added')
 | 
										text: this.$t('add-emoji.added')
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
				this.fetchEmojis();
 | 
									this.fetchEmojis();
 | 
				
			||||||
			}).catch(e => {
 | 
								}).catch(e => {
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'error',
 | 
										type: 'error',
 | 
				
			||||||
					text: e
 | 
										text: e
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
@@ -103,12 +103,12 @@ export default Vue.extend({
 | 
				
			|||||||
				url: emoji.url,
 | 
									url: emoji.url,
 | 
				
			||||||
				aliases: emoji.aliases.split(' ').filter(x => x.length > 0)
 | 
									aliases: emoji.aliases.split(' ').filter(x => x.length > 0)
 | 
				
			||||||
			}).then(() => {
 | 
								}).then(() => {
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'success',
 | 
										type: 'success',
 | 
				
			||||||
					text: this.$t('updated')
 | 
										text: this.$t('updated')
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
			}).catch(e => {
 | 
								}).catch(e => {
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'error',
 | 
										type: 'error',
 | 
				
			||||||
					text: e
 | 
										text: e
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
@@ -116,23 +116,23 @@ export default Vue.extend({
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		removeEmoji(emoji) {
 | 
							removeEmoji(emoji) {
 | 
				
			||||||
			this.$root.alert({
 | 
								this.$root.dialog({
 | 
				
			||||||
				type: 'warning',
 | 
									type: 'warning',
 | 
				
			||||||
				text: this.$t('remove-emoji.are-you-sure').replace('$1', emoji.name),
 | 
									text: this.$t('remove-emoji.are-you-sure').replace('$1', emoji.name),
 | 
				
			||||||
				showCancelButton: true
 | 
									showCancelButton: true
 | 
				
			||||||
			}).then(res => {
 | 
								}).then(({ canceled }) => {
 | 
				
			||||||
				if (!res) return;
 | 
									if (canceled) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				this.$root.api('admin/emoji/remove', {
 | 
									this.$root.api('admin/emoji/remove', {
 | 
				
			||||||
					id: emoji.id
 | 
										id: emoji.id
 | 
				
			||||||
				}).then(() => {
 | 
									}).then(() => {
 | 
				
			||||||
					this.$root.alert({
 | 
										this.$root.dialog({
 | 
				
			||||||
						type: 'success',
 | 
											type: 'success',
 | 
				
			||||||
						text: this.$t('remove-emoji.removed')
 | 
											text: this.$t('remove-emoji.removed')
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
					this.fetchEmojis();
 | 
										this.fetchEmojis();
 | 
				
			||||||
				}).catch(e => {
 | 
									}).catch(e => {
 | 
				
			||||||
					this.$root.alert({
 | 
										this.$root.dialog({
 | 
				
			||||||
						type: 'error',
 | 
											type: 'error',
 | 
				
			||||||
						text: e
 | 
											text: e
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -212,7 +212,7 @@ export default Vue.extend({
 | 
				
			|||||||
			this.$root.api('admin/invite').then(x => {
 | 
								this.$root.api('admin/invite').then(x => {
 | 
				
			||||||
				this.inviteCode = x.code;
 | 
									this.inviteCode = x.code;
 | 
				
			||||||
			}).catch(e => {
 | 
								}).catch(e => {
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'error',
 | 
										type: 'error',
 | 
				
			||||||
					text: e
 | 
										text: e
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
@@ -258,12 +258,12 @@ export default Vue.extend({
 | 
				
			|||||||
				smtpUser: this.smtpUser,
 | 
									smtpUser: this.smtpUser,
 | 
				
			||||||
				smtpPass: this.smtpPass
 | 
									smtpPass: this.smtpPass
 | 
				
			||||||
			}).then(() => {
 | 
								}).then(() => {
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'success',
 | 
										type: 'success',
 | 
				
			||||||
					text: this.$t('saved')
 | 
										text: this.$t('saved')
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
			}).catch(e => {
 | 
								}).catch(e => {
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'error',
 | 
										type: 'error',
 | 
				
			||||||
					text: e
 | 
										text: e
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,14 +34,14 @@ export default Vue.extend({
 | 
				
			|||||||
			const process = async () => {
 | 
								const process = async () => {
 | 
				
			||||||
				const user = await this.$root.api('users/show', parseAcct(this.username));
 | 
									const user = await this.$root.api('users/show', parseAcct(this.username));
 | 
				
			||||||
				await this.$root.api('admin/moderators/add', { userId: user.id });
 | 
									await this.$root.api('admin/moderators/add', { userId: user.id });
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'success',
 | 
										type: 'success',
 | 
				
			||||||
					text: this.$t('add-moderator.added')
 | 
										text: this.$t('add-moderator.added')
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
			};
 | 
								};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			await process().catch(e => {
 | 
								await process().catch(e => {
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'error',
 | 
										type: 'error',
 | 
				
			||||||
					text: e.toString()
 | 
										text: e.toString()
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -115,12 +115,12 @@ export default Vue.extend({
 | 
				
			|||||||
				return await this.$root.api('users/show', this.target.startsWith('@') ? parseAcct(this.target) : { userId: this.target });
 | 
									return await this.$root.api('users/show', this.target.startsWith('@') ? parseAcct(this.target) : { userId: this.target });
 | 
				
			||||||
			} catch (e) {
 | 
								} catch (e) {
 | 
				
			||||||
				if (e == 'user not found') {
 | 
									if (e == 'user not found') {
 | 
				
			||||||
					this.$root.alert({
 | 
										this.$root.dialog({
 | 
				
			||||||
						type: 'error',
 | 
											type: 'error',
 | 
				
			||||||
						text: this.$t('user-not-found')
 | 
											text: this.$t('user-not-found')
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					this.$root.alert({
 | 
										this.$root.dialog({
 | 
				
			||||||
						type: 'error',
 | 
											type: 'error',
 | 
				
			||||||
						text: e.toString()
 | 
											text: e.toString()
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
@@ -138,7 +138,7 @@ export default Vue.extend({
 | 
				
			|||||||
		async resetPassword() {
 | 
							async resetPassword() {
 | 
				
			||||||
			const user = await this.fetchUser();
 | 
								const user = await this.fetchUser();
 | 
				
			||||||
			this.$root.api('admin/reset-password', { userId: user.id }).then(res => {
 | 
								this.$root.api('admin/reset-password', { userId: user.id }).then(res => {
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'success',
 | 
										type: 'success',
 | 
				
			||||||
					text: this.$t('password-updated', { password: res.password })
 | 
										text: this.$t('password-updated', { password: res.password })
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
@@ -151,14 +151,14 @@ export default Vue.extend({
 | 
				
			|||||||
			const process = async () => {
 | 
								const process = async () => {
 | 
				
			||||||
				const user = await this.fetchUser();
 | 
									const user = await this.fetchUser();
 | 
				
			||||||
				await this.$root.api('admin/verify-user', { userId: user.id });
 | 
									await this.$root.api('admin/verify-user', { userId: user.id });
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'success',
 | 
										type: 'success',
 | 
				
			||||||
					text: this.$t('verified')
 | 
										text: this.$t('verified')
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
			};
 | 
								};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			await process().catch(e => {
 | 
								await process().catch(e => {
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'error',
 | 
										type: 'error',
 | 
				
			||||||
					text: e.toString()
 | 
										text: e.toString()
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
@@ -173,14 +173,14 @@ export default Vue.extend({
 | 
				
			|||||||
			const process = async () => {
 | 
								const process = async () => {
 | 
				
			||||||
				const user = await this.fetchUser();
 | 
									const user = await this.fetchUser();
 | 
				
			||||||
				await this.$root.api('admin/unverify-user', { userId: user.id });
 | 
									await this.$root.api('admin/unverify-user', { userId: user.id });
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'success',
 | 
										type: 'success',
 | 
				
			||||||
					text: this.$t('unverified')
 | 
										text: this.$t('unverified')
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
			};
 | 
								};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			await process().catch(e => {
 | 
								await process().catch(e => {
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'error',
 | 
										type: 'error',
 | 
				
			||||||
					text: e.toString()
 | 
										text: e.toString()
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
@@ -195,14 +195,14 @@ export default Vue.extend({
 | 
				
			|||||||
			const process = async () => {
 | 
								const process = async () => {
 | 
				
			||||||
				const user = await this.fetchUser();
 | 
									const user = await this.fetchUser();
 | 
				
			||||||
				await this.$root.api('admin/suspend-user', { userId: user.id });
 | 
									await this.$root.api('admin/suspend-user', { userId: user.id });
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'success',
 | 
										type: 'success',
 | 
				
			||||||
					text: this.$t('suspended')
 | 
										text: this.$t('suspended')
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
			};
 | 
								};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			await process().catch(e => {
 | 
								await process().catch(e => {
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'error',
 | 
										type: 'error',
 | 
				
			||||||
					text: e.toString()
 | 
										text: e.toString()
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
@@ -217,14 +217,14 @@ export default Vue.extend({
 | 
				
			|||||||
			const process = async () => {
 | 
								const process = async () => {
 | 
				
			||||||
				const user = await this.fetchUser();
 | 
									const user = await this.fetchUser();
 | 
				
			||||||
				await this.$root.api('admin/unsuspend-user', { userId: user.id });
 | 
									await this.$root.api('admin/unsuspend-user', { userId: user.id });
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'success',
 | 
										type: 'success',
 | 
				
			||||||
					text: this.$t('unsuspended')
 | 
										text: this.$t('unsuspended')
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
			};
 | 
								};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			await process().catch(e => {
 | 
								await process().catch(e => {
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'error',
 | 
										type: 'error',
 | 
				
			||||||
					text: e.toString()
 | 
										text: e.toString()
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,7 @@ export default async function($root: any, force = false, silent = false) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*if (!silent) {
 | 
							/*if (!silent) {
 | 
				
			||||||
			$root.alert({
 | 
								$root.dialog({
 | 
				
			||||||
				title: $root.$t('@.update-available-title'),
 | 
									title: $root.$t('@.update-available-title'),
 | 
				
			||||||
				text: $root.$t('@.update-available', { newer, current })
 | 
									text: $root.$t('@.update-available', { newer, current })
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@ export default ($root: any) => {
 | 
				
			|||||||
	require('fuckadblock');
 | 
						require('fuckadblock');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	function adBlockDetected() {
 | 
						function adBlockDetected() {
 | 
				
			||||||
		$root.alert({
 | 
							$root.dialog({
 | 
				
			||||||
			title: $root.$t('@.adblock.detected'),
 | 
								title: $root.$t('@.adblock.detected'),
 | 
				
			||||||
			text: $root.$t('@.adblock.warning')
 | 
								text: $root.$t('@.adblock.warning')
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -142,7 +142,7 @@ export default (opts: Opts = {}) => ({
 | 
				
			|||||||
			this.$root.api('notes/favorites/create', {
 | 
								this.$root.api('notes/favorites/create', {
 | 
				
			||||||
				noteId: this.appearNote.id
 | 
									noteId: this.appearNote.id
 | 
				
			||||||
			}).then(() => {
 | 
								}).then(() => {
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'success',
 | 
										type: 'success',
 | 
				
			||||||
					splash: true
 | 
										splash: true
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,10 +50,13 @@ export default Vue.extend({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	methods: {
 | 
						methods: {
 | 
				
			||||||
		regenerateToken() {
 | 
							regenerateToken() {
 | 
				
			||||||
			this.$input({
 | 
								this.$root.dialog({
 | 
				
			||||||
				title: this.$t('enter-password'),
 | 
									title: this.$t('enter-password'),
 | 
				
			||||||
 | 
									input: {
 | 
				
			||||||
					type: 'password'
 | 
										type: 'password'
 | 
				
			||||||
			}).then(password => {
 | 
									}
 | 
				
			||||||
 | 
								}).then(({ canceled, result: password }) => {
 | 
				
			||||||
 | 
									if (canceled) return;
 | 
				
			||||||
				this.$root.api('i/regenerate_token', {
 | 
									this.$root.api('i/regenerate_token', {
 | 
				
			||||||
					password: password
 | 
										password: password
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,12 +2,17 @@
 | 
				
			|||||||
<div class="felqjxyj" :class="{ splash }">
 | 
					<div class="felqjxyj" :class="{ splash }">
 | 
				
			||||||
	<div class="bg" ref="bg" @click="onBgClick"></div>
 | 
						<div class="bg" ref="bg" @click="onBgClick"></div>
 | 
				
			||||||
	<div class="main" ref="main">
 | 
						<div class="main" ref="main">
 | 
				
			||||||
		<div class="icon" :class="type"><fa :icon="icon"/></div>
 | 
							<div class="icon" v-if="!input && !select && !user" :class="type"><fa :icon="icon"/></div>
 | 
				
			||||||
		<header v-if="title" v-html="title"></header>
 | 
							<header v-if="title" v-html="title"></header>
 | 
				
			||||||
		<div class="body" v-if="text" v-html="text"></div>
 | 
							<div class="body" v-if="text" v-html="text"></div>
 | 
				
			||||||
 | 
							<ui-input v-if="input" v-model="inputValue" autofocus :type="input.type || 'text'" :placeholder="input.placeholder" @keydown="onInputKeydown"></ui-input>
 | 
				
			||||||
 | 
							<ui-input v-if="user" v-model="userInputValue" autofocus @keydown="onInputKeydown"><span slot="prefix">@</span></ui-input>
 | 
				
			||||||
 | 
							<ui-select v-if="select" v-model="selectedValue">
 | 
				
			||||||
 | 
								<option v-for="item in select.items" :value="item.value">{{ item.text }}</option>
 | 
				
			||||||
 | 
							</ui-select>
 | 
				
			||||||
		<ui-horizon-group no-grow class="buttons fit-bottom" v-if="!splash">
 | 
							<ui-horizon-group no-grow class="buttons fit-bottom" v-if="!splash">
 | 
				
			||||||
			<ui-button @click="ok" primary autofocus>OK</ui-button>
 | 
								<ui-button @click="ok" primary :autofocus="!input && !select && !user">OK</ui-button>
 | 
				
			||||||
			<ui-button @click="cancel" v-if="showCancelButton">Cancel</ui-button>
 | 
								<ui-button @click="cancel" v-if="showCancelButton || input || select || user">Cancel</ui-button>
 | 
				
			||||||
		</ui-horizon-group>
 | 
							</ui-horizon-group>
 | 
				
			||||||
	</div>
 | 
						</div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
@@ -17,6 +22,7 @@
 | 
				
			|||||||
import Vue from 'vue';
 | 
					import Vue from 'vue';
 | 
				
			||||||
import * as anime from 'animejs';
 | 
					import * as anime from 'animejs';
 | 
				
			||||||
import { faTimesCircle, faQuestionCircle } from '@fortawesome/free-regular-svg-icons';
 | 
					import { faTimesCircle, faQuestionCircle } from '@fortawesome/free-regular-svg-icons';
 | 
				
			||||||
 | 
					import parseAcct from "../../../../../misc/acct/parse";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default Vue.extend({
 | 
					export default Vue.extend({
 | 
				
			||||||
	props: {
 | 
						props: {
 | 
				
			||||||
@@ -33,6 +39,15 @@ export default Vue.extend({
 | 
				
			|||||||
			type: String,
 | 
								type: String,
 | 
				
			||||||
			required: false
 | 
								required: false
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							input: {
 | 
				
			||||||
 | 
								required: false
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							select: {
 | 
				
			||||||
 | 
								required: false
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							user: {
 | 
				
			||||||
 | 
								required: false
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
		showCancelButton: {
 | 
							showCancelButton: {
 | 
				
			||||||
			type: Boolean,
 | 
								type: Boolean,
 | 
				
			||||||
			default: false
 | 
								default: false
 | 
				
			||||||
@@ -43,6 +58,14 @@ export default Vue.extend({
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data() {
 | 
				
			||||||
 | 
							return {
 | 
				
			||||||
 | 
								inputValue: this.input && this.input.default ? this.input.default : null,
 | 
				
			||||||
 | 
								userInputValue: null,
 | 
				
			||||||
 | 
								selectedValue: null
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	computed: {
 | 
						computed: {
 | 
				
			||||||
		icon(): any {
 | 
							icon(): any {
 | 
				
			||||||
			switch (this.type) {
 | 
								switch (this.type) {
 | 
				
			||||||
@@ -82,9 +105,21 @@ export default Vue.extend({
 | 
				
			|||||||
	},
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	methods: {
 | 
						methods: {
 | 
				
			||||||
		ok() {
 | 
							async ok() {
 | 
				
			||||||
			this.$emit('ok');
 | 
								if (this.user) {
 | 
				
			||||||
 | 
									const user = await this.$root.api('users/show', parseAcct(this.userInputValue));
 | 
				
			||||||
 | 
									if (user) {
 | 
				
			||||||
 | 
										this.$emit('ok', user);
 | 
				
			||||||
					this.close();
 | 
										this.close();
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									const result =
 | 
				
			||||||
 | 
										this.input ? this.inputValue :
 | 
				
			||||||
 | 
										this.select ? this.selectedValue :
 | 
				
			||||||
 | 
										true;
 | 
				
			||||||
 | 
									this.$emit('ok', result);
 | 
				
			||||||
 | 
									this.close();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		cancel() {
 | 
							cancel() {
 | 
				
			||||||
@@ -114,6 +149,14 @@ export default Vue.extend({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		onBgClick() {
 | 
							onBgClick() {
 | 
				
			||||||
			this.cancel();
 | 
								this.cancel();
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							onInputKeydown(e) {
 | 
				
			||||||
 | 
								if (e.which == 13) { // Enter
 | 
				
			||||||
 | 
									e.preventDefault();
 | 
				
			||||||
 | 
									e.stopPropagation();
 | 
				
			||||||
 | 
									this.ok();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
@@ -180,8 +223,11 @@ export default Vue.extend({
 | 
				
			|||||||
				display block
 | 
									display block
 | 
				
			||||||
				margin 0 auto
 | 
									margin 0 auto
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								& + header
 | 
				
			||||||
 | 
									margin-top 16px
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		> header
 | 
							> header
 | 
				
			||||||
			margin 16px 0 8px 0
 | 
								margin 0 0 8px 0
 | 
				
			||||||
			font-weight bold
 | 
								font-weight bold
 | 
				
			||||||
			font-size 20px
 | 
								font-size 20px
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -99,13 +99,14 @@ export default Vue.extend({
 | 
				
			|||||||
			this.$emit('go', game);
 | 
								this.$emit('go', game);
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		match() {
 | 
							async match() {
 | 
				
			||||||
			this.$input({
 | 
								const { result: user } = await this.$root.dialog({
 | 
				
			||||||
				title: this.$t('enter-username')
 | 
									title: this.$t('enter-username'),
 | 
				
			||||||
			}).then(username => {
 | 
									user: {
 | 
				
			||||||
				this.$root.api('users/show', {
 | 
										local: true
 | 
				
			||||||
					username
 | 
									}
 | 
				
			||||||
				}).then(user => {
 | 
								});
 | 
				
			||||||
 | 
								if (user == null) return;
 | 
				
			||||||
			this.$root.api('games/reversi/match', {
 | 
								this.$root.api('games/reversi/match', {
 | 
				
			||||||
				userId: user.id
 | 
									userId: user.id
 | 
				
			||||||
			}).then(res => {
 | 
								}).then(res => {
 | 
				
			||||||
@@ -115,8 +116,6 @@ export default Vue.extend({
 | 
				
			|||||||
					this.$emit('go', res);
 | 
										this.$emit('go', res);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
				});
 | 
					 | 
				
			||||||
			});
 | 
					 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		accept(invitation) {
 | 
							accept(invitation) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
<div class="onchrpzrvnoruiaenfcqvccjfuupzzwv">
 | 
					<div class="onchrpzrvnoruiaenfcqvccjfuupzzwv" :class="{ big: $root.isMobile }">
 | 
				
			||||||
	<div class="backdrop" ref="backdrop" @click="close"></div>
 | 
						<div class="backdrop" ref="backdrop" @click="close"></div>
 | 
				
			||||||
	<div class="popover" :class="{ hukidasi }" ref="popover">
 | 
						<div class="popover" :class="{ hukidasi }" ref="popover">
 | 
				
			||||||
		<template v-for="item, i in items">
 | 
							<template v-for="item, i in items">
 | 
				
			||||||
@@ -125,6 +125,11 @@ export default Vue.extend({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	position initial
 | 
						position initial
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						&.big
 | 
				
			||||||
 | 
							> .popover
 | 
				
			||||||
 | 
								> button
 | 
				
			||||||
 | 
									font-size 15px
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	> .backdrop
 | 
						> .backdrop
 | 
				
			||||||
		position fixed
 | 
							position fixed
 | 
				
			||||||
		top 0
 | 
							top 0
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -78,7 +78,7 @@ export default Vue.extend({
 | 
				
			|||||||
			this.$root.api('i/pin', {
 | 
								this.$root.api('i/pin', {
 | 
				
			||||||
				noteId: this.note.id
 | 
									noteId: this.note.id
 | 
				
			||||||
			}).then(() => {
 | 
								}).then(() => {
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'success',
 | 
										type: 'success',
 | 
				
			||||||
					splash: true
 | 
										splash: true
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
@@ -95,12 +95,12 @@ export default Vue.extend({
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		del() {
 | 
							del() {
 | 
				
			||||||
			this.$root.alert({
 | 
								this.$root.dialog({
 | 
				
			||||||
				type: 'warning',
 | 
									type: 'warning',
 | 
				
			||||||
				text: this.$t('delete-confirm'),
 | 
									text: this.$t('delete-confirm'),
 | 
				
			||||||
				showCancelButton: true
 | 
									showCancelButton: true
 | 
				
			||||||
			}).then(res => {
 | 
								}).then(({ canceled }) => {
 | 
				
			||||||
				if (!res) return;
 | 
									if (canceled) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				this.$root.api('notes/delete', {
 | 
									this.$root.api('notes/delete', {
 | 
				
			||||||
					noteId: this.note.id
 | 
										noteId: this.note.id
 | 
				
			||||||
@@ -114,7 +114,7 @@ export default Vue.extend({
 | 
				
			|||||||
			this.$root.api('notes/favorites/create', {
 | 
								this.$root.api('notes/favorites/create', {
 | 
				
			||||||
				noteId: this.note.id
 | 
									noteId: this.note.id
 | 
				
			||||||
			}).then(() => {
 | 
								}).then(() => {
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'success',
 | 
										type: 'success',
 | 
				
			||||||
					splash: true
 | 
										splash: true
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
@@ -126,7 +126,7 @@ export default Vue.extend({
 | 
				
			|||||||
			this.$root.api('notes/favorites/delete', {
 | 
								this.$root.api('notes/favorites/delete', {
 | 
				
			||||||
				noteId: this.note.id
 | 
									noteId: this.note.id
 | 
				
			||||||
			}).then(() => {
 | 
								}).then(() => {
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'success',
 | 
										type: 'success',
 | 
				
			||||||
					splash: true
 | 
										splash: true
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,21 +11,33 @@ import i18n from '../../../i18n';
 | 
				
			|||||||
export default Vue.extend({
 | 
					export default Vue.extend({
 | 
				
			||||||
	i18n: i18n('common/views/components/password-settings.vue'),
 | 
						i18n: i18n('common/views/components/password-settings.vue'),
 | 
				
			||||||
	methods: {
 | 
						methods: {
 | 
				
			||||||
		reset() {
 | 
							async reset() {
 | 
				
			||||||
			this.$input({
 | 
								const { canceled: canceled1, result: currentPassword } = await this.$root.dialog({
 | 
				
			||||||
				title: this.$t('enter-current-password'),
 | 
									title: this.$t('enter-current-password'),
 | 
				
			||||||
 | 
									input: {
 | 
				
			||||||
					type: 'password'
 | 
										type: 'password'
 | 
				
			||||||
			}).then(currentPassword => {
 | 
									}
 | 
				
			||||||
				this.$input({
 | 
								});
 | 
				
			||||||
 | 
								if (canceled1) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								const { canceled: canceled2, result: newPassword } = await this.$root.dialog({
 | 
				
			||||||
				title: this.$t('enter-new-password'),
 | 
									title: this.$t('enter-new-password'),
 | 
				
			||||||
 | 
									input: {
 | 
				
			||||||
					type: 'password'
 | 
										type: 'password'
 | 
				
			||||||
				}).then(newPassword => {
 | 
									}
 | 
				
			||||||
					this.$input({
 | 
								});
 | 
				
			||||||
 | 
								if (canceled2) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								const { canceled: canceled3, result: newPassword2 } = await this.$root.dialog({
 | 
				
			||||||
				title: this.$t('enter-new-password-again'),
 | 
									title: this.$t('enter-new-password-again'),
 | 
				
			||||||
 | 
									input: {
 | 
				
			||||||
					type: 'password'
 | 
										type: 'password'
 | 
				
			||||||
					}).then(newPassword2 => {
 | 
									}
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
								if (canceled3) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (newPassword !== newPassword2) {
 | 
								if (newPassword !== newPassword2) {
 | 
				
			||||||
							this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					title: null,
 | 
										title: null,
 | 
				
			||||||
					text: this.$t('not-match')
 | 
										text: this.$t('not-match')
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
@@ -37,9 +49,6 @@ export default Vue.extend({
 | 
				
			|||||||
			}).then(() => {
 | 
								}).then(() => {
 | 
				
			||||||
				this.$notify(this.$t('changed'));
 | 
									this.$notify(this.$t('changed'));
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
					});
 | 
					 | 
				
			||||||
				});
 | 
					 | 
				
			||||||
			});
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -213,7 +213,7 @@ export default Vue.extend({
 | 
				
			|||||||
				this.$store.state.i.bannerUrl = i.bannerUrl;
 | 
									this.$store.state.i.bannerUrl = i.bannerUrl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (notify) {
 | 
									if (notify) {
 | 
				
			||||||
					this.$root.alert({
 | 
										this.$root.dialog({
 | 
				
			||||||
						type: 'success',
 | 
											type: 'success',
 | 
				
			||||||
						text: this.$t('saved')
 | 
											text: this.$t('saved')
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
@@ -222,10 +222,13 @@ export default Vue.extend({
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		updateEmail() {
 | 
							updateEmail() {
 | 
				
			||||||
			this.$input({
 | 
								this.$root.dialog({
 | 
				
			||||||
				title: this.$t('@.enter-password'),
 | 
									title: this.$t('@.enter-password'),
 | 
				
			||||||
 | 
									input: {
 | 
				
			||||||
					type: 'password'
 | 
										type: 'password'
 | 
				
			||||||
			}).then(password => {
 | 
									}
 | 
				
			||||||
 | 
								}).then(({ canceled, result: password }) => {
 | 
				
			||||||
 | 
									if (canceled) return;
 | 
				
			||||||
				this.$root.api('i/update_email', {
 | 
									this.$root.api('i/update_email', {
 | 
				
			||||||
					password: password,
 | 
										password: password,
 | 
				
			||||||
					email: this.email == '' ? null : this.email
 | 
										email: this.email == '' ? null : this.email
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -223,7 +223,7 @@ export default Vue.extend({
 | 
				
			|||||||
			try {
 | 
								try {
 | 
				
			||||||
				theme = JSON5.parse(code);
 | 
									theme = JSON5.parse(code);
 | 
				
			||||||
			} catch (e) {
 | 
								} catch (e) {
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'error',
 | 
										type: 'error',
 | 
				
			||||||
					text: this.$t('invalid-theme')
 | 
										text: this.$t('invalid-theme')
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
@@ -236,7 +236,7 @@ export default Vue.extend({
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (theme.id == null) {
 | 
								if (theme.id == null) {
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'error',
 | 
										type: 'error',
 | 
				
			||||||
					text: this.$t('invalid-theme')
 | 
										text: this.$t('invalid-theme')
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
@@ -244,7 +244,7 @@ export default Vue.extend({
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (this.$store.state.device.themes.some(t => t.id == theme.id)) {
 | 
								if (this.$store.state.device.themes.some(t => t.id == theme.id)) {
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'info',
 | 
										type: 'info',
 | 
				
			||||||
					text: this.$t('already-installed')
 | 
										text: this.$t('already-installed')
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
@@ -256,7 +256,7 @@ export default Vue.extend({
 | 
				
			|||||||
				key: 'themes', value: themes
 | 
									key: 'themes', value: themes
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			this.$root.alert({
 | 
								this.$root.dialog({
 | 
				
			||||||
				type: 'success',
 | 
									type: 'success',
 | 
				
			||||||
				text: this.$t('installed').replace('{}', theme.name)
 | 
									text: this.$t('installed').replace('{}', theme.name)
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
@@ -269,7 +269,7 @@ export default Vue.extend({
 | 
				
			|||||||
				key: 'themes', value: themes
 | 
									key: 'themes', value: themes
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			this.$root.alert({
 | 
								this.$root.dialog({
 | 
				
			||||||
				type: 'info',
 | 
									type: 'info',
 | 
				
			||||||
				text: this.$t('uninstalled').replace('{}', theme.name)
 | 
									text: this.$t('uninstalled').replace('{}', theme.name)
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
@@ -306,7 +306,7 @@ export default Vue.extend({
 | 
				
			|||||||
			const theme = this.myTheme;
 | 
								const theme = this.myTheme;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (theme.name == null || theme.name.trim() == '') {
 | 
								if (theme.name == null || theme.name.trim() == '') {
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					type: 'warning',
 | 
										type: 'warning',
 | 
				
			||||||
					text: this.$t('theme-name-required')
 | 
										text: this.$t('theme-name-required')
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
@@ -320,7 +320,7 @@ export default Vue.extend({
 | 
				
			|||||||
				key: 'themes', value: themes
 | 
									key: 'themes', value: themes
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			this.$root.alert({
 | 
								this.$root.dialog({
 | 
				
			||||||
				type: 'success',
 | 
									type: 'success',
 | 
				
			||||||
				text: this.$t('saved')
 | 
									text: this.$t('saved')
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,17 +14,19 @@
 | 
				
			|||||||
				:disabled="disabled"
 | 
									:disabled="disabled"
 | 
				
			||||||
				:required="required"
 | 
									:required="required"
 | 
				
			||||||
				:readonly="readonly"
 | 
									:readonly="readonly"
 | 
				
			||||||
 | 
									:placeholder="placeholder"
 | 
				
			||||||
				:pattern="pattern"
 | 
									:pattern="pattern"
 | 
				
			||||||
				:autocomplete="autocomplete"
 | 
									:autocomplete="autocomplete"
 | 
				
			||||||
				:spellcheck="spellcheck"
 | 
									:spellcheck="spellcheck"
 | 
				
			||||||
				@focus="focused = true"
 | 
									@focus="focused = true"
 | 
				
			||||||
				@blur="focused = false"
 | 
									@blur="focused = false"
 | 
				
			||||||
 | 
									@keydown="$emit('keydown', $event)"
 | 
				
			||||||
			>
 | 
								>
 | 
				
			||||||
		</template>
 | 
							</template>
 | 
				
			||||||
		<template v-else>
 | 
							<template v-else>
 | 
				
			||||||
			<input ref="input"
 | 
								<input ref="input"
 | 
				
			||||||
				type="text"
 | 
									type="text"
 | 
				
			||||||
				:value="placeholder"
 | 
									:value="filePlaceholder"
 | 
				
			||||||
				readonly
 | 
									readonly
 | 
				
			||||||
				@click="chooseFile"
 | 
									@click="chooseFile"
 | 
				
			||||||
			>
 | 
								>
 | 
				
			||||||
@@ -74,6 +76,15 @@ export default Vue.extend({
 | 
				
			|||||||
			type: String,
 | 
								type: String,
 | 
				
			||||||
			required: false
 | 
								required: false
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							placeholder: {
 | 
				
			||||||
 | 
								type: String,
 | 
				
			||||||
 | 
								required: false
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							autofocus: {
 | 
				
			||||||
 | 
								type: Boolean,
 | 
				
			||||||
 | 
								required: false,
 | 
				
			||||||
 | 
								default: false
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
		autocomplete: {
 | 
							autocomplete: {
 | 
				
			||||||
			required: false
 | 
								required: false
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -109,7 +120,7 @@ export default Vue.extend({
 | 
				
			|||||||
		filled(): boolean {
 | 
							filled(): boolean {
 | 
				
			||||||
			return this.v != '' && this.v != null;
 | 
								return this.v != '' && this.v != null;
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		placeholder(): string {
 | 
							filePlaceholder(): string {
 | 
				
			||||||
			if (this.type != 'file') return null;
 | 
								if (this.type != 'file') return null;
 | 
				
			||||||
			if (this.v == null) return null;
 | 
								if (this.v == null) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -142,6 +153,12 @@ export default Vue.extend({
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	mounted() {
 | 
						mounted() {
 | 
				
			||||||
 | 
							if (this.autofocus) {
 | 
				
			||||||
 | 
								this.$nextTick(() => {
 | 
				
			||||||
 | 
									this.$refs.input.focus();
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		this.$nextTick(() => {
 | 
							this.$nextTick(() => {
 | 
				
			||||||
			if (this.$refs.prefix) {
 | 
								if (this.$refs.prefix) {
 | 
				
			||||||
				this.$refs.label.style.left = (this.$refs.prefix.offsetLeft + this.$refs.prefix.offsetWidth) + 'px';
 | 
									this.$refs.label.style.left = (this.$refs.prefix.offsetLeft + this.$refs.prefix.offsetWidth) + 'px';
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@ export default ($root: any) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		const regex = RegExp('\.(jpg|jpeg|png|gif|webp|bmp|tiff)$');
 | 
							const regex = RegExp('\.(jpg|jpeg|png|gif|webp|bmp|tiff)$');
 | 
				
			||||||
		if (!regex.test(file.name) ) {
 | 
							if (!regex.test(file.name) ) {
 | 
				
			||||||
			$root.alert({
 | 
								$root.dialog({
 | 
				
			||||||
				title: '%fa:info-circle% %i18n:desktop.invalid-filetype%',
 | 
									title: '%fa:info-circle% %i18n:desktop.invalid-filetype%',
 | 
				
			||||||
				text: null
 | 
									text: null
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
@@ -87,7 +87,7 @@ export default ($root: any) => {
 | 
				
			|||||||
				value: i.avatarUrl
 | 
									value: i.avatarUrl
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			$root.alert({
 | 
								$root.dialog({
 | 
				
			||||||
				title: '%fa:info-circle% %i18n:desktop.avatar-updated%',
 | 
									title: '%fa:info-circle% %i18n:desktop.avatar-updated%',
 | 
				
			||||||
				text: null
 | 
									text: null
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -87,7 +87,7 @@ export default ($root: any) => {
 | 
				
			|||||||
				value: i.bannerUrl
 | 
									value: i.bannerUrl
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			$root.alert({
 | 
								$root.dialog({
 | 
				
			||||||
				title: '%fa:info-circle% %i18n:desktop.banner-updated%',
 | 
									title: '%fa:info-circle% %i18n:desktop.banner-updated%',
 | 
				
			||||||
				text: null
 | 
									text: null
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,7 +34,6 @@ import PostFormWindow from './views/components/post-form-window.vue';
 | 
				
			|||||||
import RenoteFormWindow from './views/components/renote-form-window.vue';
 | 
					import RenoteFormWindow from './views/components/renote-form-window.vue';
 | 
				
			||||||
import MkChooseFileFromDriveWindow from './views/components/choose-file-from-drive-window.vue';
 | 
					import MkChooseFileFromDriveWindow from './views/components/choose-file-from-drive-window.vue';
 | 
				
			||||||
import MkChooseFolderFromDriveWindow from './views/components/choose-folder-from-drive-window.vue';
 | 
					import MkChooseFolderFromDriveWindow from './views/components/choose-folder-from-drive-window.vue';
 | 
				
			||||||
import InputDialog from './views/components/input-dialog.vue';
 | 
					 | 
				
			||||||
import Notification from './views/components/ui-notification.vue';
 | 
					import Notification from './views/components/ui-notification.vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { url } from '../config';
 | 
					import { url } from '../config';
 | 
				
			||||||
@@ -113,22 +112,6 @@ init(async (launch) => {
 | 
				
			|||||||
				});
 | 
									});
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			$input(opts) {
 | 
					 | 
				
			||||||
				return new Promise<string>((res, rej) => {
 | 
					 | 
				
			||||||
					const o = opts || {};
 | 
					 | 
				
			||||||
					const d = this.$root.new(InputDialog, {
 | 
					 | 
				
			||||||
						title: o.title,
 | 
					 | 
				
			||||||
						placeholder: o.placeholder,
 | 
					 | 
				
			||||||
						default: o.default,
 | 
					 | 
				
			||||||
						type: o.type || 'text',
 | 
					 | 
				
			||||||
						allowEmpty: o.allowEmpty
 | 
					 | 
				
			||||||
					});
 | 
					 | 
				
			||||||
					d.$once('done', text => {
 | 
					 | 
				
			||||||
						res(text);
 | 
					 | 
				
			||||||
					});
 | 
					 | 
				
			||||||
				});
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			$notify(message) {
 | 
								$notify(message) {
 | 
				
			||||||
				this.$root.new(Notification, {
 | 
									this.$root.new(Notification, {
 | 
				
			||||||
					message
 | 
										message
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -148,12 +148,15 @@ export default Vue.extend({
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rename() {
 | 
							rename() {
 | 
				
			||||||
			this.$input({
 | 
								this.$root.dialog({
 | 
				
			||||||
				title: this.$t('contextmenu.rename-file'),
 | 
									title: this.$t('contextmenu.rename-file'),
 | 
				
			||||||
 | 
									input: {
 | 
				
			||||||
					placeholder: this.$t('contextmenu.input-new-file-name'),
 | 
										placeholder: this.$t('contextmenu.input-new-file-name'),
 | 
				
			||||||
					default: this.file.name,
 | 
										default: this.file.name,
 | 
				
			||||||
					allowEmpty: false
 | 
										allowEmpty: false
 | 
				
			||||||
			}).then(name => {
 | 
									}
 | 
				
			||||||
 | 
								}).then(({ canceled, result: name }) => {
 | 
				
			||||||
 | 
									if (canceled) return;
 | 
				
			||||||
				this.$root.api('drive/files/update', {
 | 
									this.$root.api('drive/files/update', {
 | 
				
			||||||
					fileId: this.file.id,
 | 
										fileId: this.file.id,
 | 
				
			||||||
					name: name
 | 
										name: name
 | 
				
			||||||
@@ -170,7 +173,7 @@ export default Vue.extend({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		copyUrl() {
 | 
							copyUrl() {
 | 
				
			||||||
			copyToClipboard(this.file.url);
 | 
								copyToClipboard(this.file.url);
 | 
				
			||||||
			this.$root.alert({
 | 
								this.$root.dialog({
 | 
				
			||||||
				title: this.$t('contextmenu.copied'),
 | 
									title: this.$t('contextmenu.copied'),
 | 
				
			||||||
				text: this.$t('contextmenu.copied-url-to-clipboard')
 | 
									text: this.$t('contextmenu.copied-url-to-clipboard')
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -155,7 +155,7 @@ export default Vue.extend({
 | 
				
			|||||||
				}).catch(err => {
 | 
									}).catch(err => {
 | 
				
			||||||
					switch (err) {
 | 
										switch (err) {
 | 
				
			||||||
						case 'detected-circular-definition':
 | 
											case 'detected-circular-definition':
 | 
				
			||||||
							this.$root.alert({
 | 
												this.$root.dialog({
 | 
				
			||||||
								title: this.$t('unable-to-process'),
 | 
													title: this.$t('unable-to-process'),
 | 
				
			||||||
								text: this.$t('circular-reference-detected')
 | 
													text: this.$t('circular-reference-detected')
 | 
				
			||||||
							});
 | 
												});
 | 
				
			||||||
@@ -192,11 +192,14 @@ export default Vue.extend({
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rename() {
 | 
							rename() {
 | 
				
			||||||
			this.$input({
 | 
								this.$root.dialog({
 | 
				
			||||||
				title: this.$t('contextmenu.rename-folder'),
 | 
									title: this.$t('contextmenu.rename-folder'),
 | 
				
			||||||
 | 
									input: {
 | 
				
			||||||
					placeholder: this.$t('contextmenu.input-new-folder-name'),
 | 
										placeholder: this.$t('contextmenu.input-new-folder-name'),
 | 
				
			||||||
					default: this.folder.name
 | 
										default: this.folder.name
 | 
				
			||||||
			}).then(name => {
 | 
									}
 | 
				
			||||||
 | 
								}).then(({ canceled, result: name }) => {
 | 
				
			||||||
 | 
									if (canceled) return;
 | 
				
			||||||
				this.$root.api('drive/folders/update', {
 | 
									this.$root.api('drive/folders/update', {
 | 
				
			||||||
					folderId: this.folder.id,
 | 
										folderId: this.folder.id,
 | 
				
			||||||
					name: name
 | 
										name: name
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -313,7 +313,7 @@ export default Vue.extend({
 | 
				
			|||||||
				}).catch(err => {
 | 
									}).catch(err => {
 | 
				
			||||||
					switch (err) {
 | 
										switch (err) {
 | 
				
			||||||
						case 'detected-circular-definition':
 | 
											case 'detected-circular-definition':
 | 
				
			||||||
							this.$root.alert({
 | 
												this.$root.dialog({
 | 
				
			||||||
								title: this.$t('unable-to-process'),
 | 
													title: this.$t('unable-to-process'),
 | 
				
			||||||
								text: this.$t('circular-reference-detected')
 | 
													text: this.$t('circular-reference-detected')
 | 
				
			||||||
							});
 | 
												});
 | 
				
			||||||
@@ -331,16 +331,19 @@ export default Vue.extend({
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		urlUpload() {
 | 
							urlUpload() {
 | 
				
			||||||
			this.$input({
 | 
								this.$root.dialog({
 | 
				
			||||||
				title: this.$t('url-upload'),
 | 
									title: this.$t('url-upload'),
 | 
				
			||||||
 | 
									input: {
 | 
				
			||||||
					placeholder: this.$t('url-of-file')
 | 
										placeholder: this.$t('url-of-file')
 | 
				
			||||||
			}).then(url => {
 | 
									}
 | 
				
			||||||
 | 
								}).then(({ canceled, result: url }) => {
 | 
				
			||||||
 | 
									if (canceled) return;
 | 
				
			||||||
				this.$root.api('drive/files/upload_from_url', {
 | 
									this.$root.api('drive/files/upload_from_url', {
 | 
				
			||||||
					url: url,
 | 
										url: url,
 | 
				
			||||||
					folderId: this.folder ? this.folder.id : undefined
 | 
										folderId: this.folder ? this.folder.id : undefined
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
					title: this.$t('url-upload-requested'),
 | 
										title: this.$t('url-upload-requested'),
 | 
				
			||||||
					text: this.$t('may-take-time')
 | 
										text: this.$t('may-take-time')
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
@@ -348,10 +351,13 @@ export default Vue.extend({
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		createFolder() {
 | 
							createFolder() {
 | 
				
			||||||
			this.$input({
 | 
								this.$root.dialog({
 | 
				
			||||||
				title: this.$t('create-folder'),
 | 
									title: this.$t('create-folder'),
 | 
				
			||||||
 | 
									input: {
 | 
				
			||||||
					placeholder: this.$t('folder-name')
 | 
										placeholder: this.$t('folder-name')
 | 
				
			||||||
			}).then(name => {
 | 
									}
 | 
				
			||||||
 | 
								}).then(({ canceled, result: name }) => {
 | 
				
			||||||
 | 
									if (canceled) return;
 | 
				
			||||||
				this.$root.api('drive/folders/create', {
 | 
									this.$root.api('drive/folders/create', {
 | 
				
			||||||
					name: name,
 | 
										name: name,
 | 
				
			||||||
					parentId: this.folder ? this.folder.id : undefined
 | 
										parentId: this.folder ? this.folder.id : undefined
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -186,7 +186,7 @@ export default Vue.extend({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	methods: {
 | 
						methods: {
 | 
				
			||||||
		hint() {
 | 
							hint() {
 | 
				
			||||||
			this.$root.alert({
 | 
								this.$root.dialog({
 | 
				
			||||||
				title: this.$t('@.customization-tips.title'),
 | 
									title: this.$t('@.customization-tips.title'),
 | 
				
			||||||
				text: this.$t('@.customization-tips.paragraph')
 | 
									text: this.$t('@.customization-tips.paragraph')
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,180 +0,0 @@
 | 
				
			|||||||
<template>
 | 
					 | 
				
			||||||
<mk-window ref="window" is-modal width="500px" @before-close="beforeClose" @closed="destroyDom">
 | 
					 | 
				
			||||||
	<span slot="header" :class="$style.header">
 | 
					 | 
				
			||||||
		<fa icon="i-cursor"/>{{ title }}
 | 
					 | 
				
			||||||
	</span>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	<div :class="$style.body">
 | 
					 | 
				
			||||||
		<input ref="text" v-model="text" :type="type" @keydown="onKeydown" :placeholder="placeholder"/>
 | 
					 | 
				
			||||||
	</div>
 | 
					 | 
				
			||||||
	<div :class="$style.actions">
 | 
					 | 
				
			||||||
		<button :class="$style.cancel" @click="cancel">{{ $t('cancel') }}</button>
 | 
					 | 
				
			||||||
		<button :class="$style.ok" :disabled="!allowEmpty && text.length == 0" @click="ok">{{ $t('ok') }}</button>
 | 
					 | 
				
			||||||
	</div>
 | 
					 | 
				
			||||||
</mk-window>
 | 
					 | 
				
			||||||
</template>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<script lang="ts">
 | 
					 | 
				
			||||||
import Vue from 'vue';
 | 
					 | 
				
			||||||
import i18n from '../../../i18n';
 | 
					 | 
				
			||||||
export default Vue.extend({
 | 
					 | 
				
			||||||
	i18n: i18n('desktop/views/input-dialog.vue'),
 | 
					 | 
				
			||||||
	props: {
 | 
					 | 
				
			||||||
		title: {
 | 
					 | 
				
			||||||
			type: String
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		placeholder: {
 | 
					 | 
				
			||||||
			type: String
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		default: {
 | 
					 | 
				
			||||||
			type: String
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		allowEmpty: {
 | 
					 | 
				
			||||||
			default: true
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		type: {
 | 
					 | 
				
			||||||
			default: 'text'
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	data() {
 | 
					 | 
				
			||||||
		return {
 | 
					 | 
				
			||||||
			done: false,
 | 
					 | 
				
			||||||
			text: ''
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	mounted() {
 | 
					 | 
				
			||||||
		if (this.default) this.text = this.default;
 | 
					 | 
				
			||||||
		this.$nextTick(() => {
 | 
					 | 
				
			||||||
			(this.$refs.text as any).focus();
 | 
					 | 
				
			||||||
		});
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
	methods: {
 | 
					 | 
				
			||||||
		ok() {
 | 
					 | 
				
			||||||
			if (!this.allowEmpty && this.text == '') return;
 | 
					 | 
				
			||||||
			this.done = true;
 | 
					 | 
				
			||||||
			(this.$refs.window as any).close();
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		cancel() {
 | 
					 | 
				
			||||||
			this.done = false;
 | 
					 | 
				
			||||||
			(this.$refs.window as any).close();
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		beforeClose() {
 | 
					 | 
				
			||||||
			if (this.done) {
 | 
					 | 
				
			||||||
				this.$emit('done', this.text);
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				this.$emit('canceled');
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		onKeydown(e) {
 | 
					 | 
				
			||||||
			if (e.which == 13) { // Enter
 | 
					 | 
				
			||||||
				e.preventDefault();
 | 
					 | 
				
			||||||
				e.stopPropagation();
 | 
					 | 
				
			||||||
				this.ok();
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<style lang="stylus" module>
 | 
					 | 
				
			||||||
.header
 | 
					 | 
				
			||||||
	> [data-icon]
 | 
					 | 
				
			||||||
		margin-right 4px
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.body
 | 
					 | 
				
			||||||
	padding 16px
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	> input
 | 
					 | 
				
			||||||
		display block
 | 
					 | 
				
			||||||
		padding 8px
 | 
					 | 
				
			||||||
		margin 0
 | 
					 | 
				
			||||||
		width 100%
 | 
					 | 
				
			||||||
		max-width 100%
 | 
					 | 
				
			||||||
		min-width 100%
 | 
					 | 
				
			||||||
		font-size 1em
 | 
					 | 
				
			||||||
		color #333
 | 
					 | 
				
			||||||
		background #fff
 | 
					 | 
				
			||||||
		outline none
 | 
					 | 
				
			||||||
		border solid 1px var(--primaryAlpha01)
 | 
					 | 
				
			||||||
		border-radius 4px
 | 
					 | 
				
			||||||
		transition border-color .3s ease
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		&:hover
 | 
					 | 
				
			||||||
			border-color var(--primaryAlpha02)
 | 
					 | 
				
			||||||
			transition border-color .1s ease
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		&:focus
 | 
					 | 
				
			||||||
			color var(--primary)
 | 
					 | 
				
			||||||
			border-color var(--primaryAlpha05)
 | 
					 | 
				
			||||||
			transition border-color 0s ease
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		&::-webkit-input-placeholder
 | 
					 | 
				
			||||||
			color var(--primaryAlpha03)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.actions
 | 
					 | 
				
			||||||
	height 72px
 | 
					 | 
				
			||||||
	background var(--primaryLighten95)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.ok
 | 
					 | 
				
			||||||
.cancel
 | 
					 | 
				
			||||||
	display block
 | 
					 | 
				
			||||||
	position absolute
 | 
					 | 
				
			||||||
	bottom 16px
 | 
					 | 
				
			||||||
	cursor pointer
 | 
					 | 
				
			||||||
	padding 0
 | 
					 | 
				
			||||||
	margin 0
 | 
					 | 
				
			||||||
	width 120px
 | 
					 | 
				
			||||||
	height 40px
 | 
					 | 
				
			||||||
	font-size 1em
 | 
					 | 
				
			||||||
	outline none
 | 
					 | 
				
			||||||
	border-radius 4px
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	&:focus
 | 
					 | 
				
			||||||
		&:after
 | 
					 | 
				
			||||||
			content ""
 | 
					 | 
				
			||||||
			pointer-events none
 | 
					 | 
				
			||||||
			position absolute
 | 
					 | 
				
			||||||
			top -5px
 | 
					 | 
				
			||||||
			right -5px
 | 
					 | 
				
			||||||
			bottom -5px
 | 
					 | 
				
			||||||
			left -5px
 | 
					 | 
				
			||||||
			border 2px solid var(--primaryAlpha03)
 | 
					 | 
				
			||||||
			border-radius 8px
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	&:disabled
 | 
					 | 
				
			||||||
		opacity 0.7
 | 
					 | 
				
			||||||
		cursor default
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.ok
 | 
					 | 
				
			||||||
	right 16px
 | 
					 | 
				
			||||||
	color var(--primaryForeground)
 | 
					 | 
				
			||||||
	background linear-gradient(to bottom, var(--primaryLighten25) 0%, var(--primaryLighten10) 100%)
 | 
					 | 
				
			||||||
	border solid 1px var(--primaryLighten15)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	&:not(:disabled)
 | 
					 | 
				
			||||||
		font-weight bold
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	&:hover:not(:disabled)
 | 
					 | 
				
			||||||
		background linear-gradient(to bottom, var(--primaryLighten8) 0%, var(--primaryDarken8) 100%)
 | 
					 | 
				
			||||||
		border-color var(--primary)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	&:active:not(:disabled)
 | 
					 | 
				
			||||||
		background var(--primary)
 | 
					 | 
				
			||||||
		border-color var(--primary)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.cancel
 | 
					 | 
				
			||||||
	right 148px
 | 
					 | 
				
			||||||
	color #888
 | 
					 | 
				
			||||||
	background linear-gradient(to bottom, #ffffff 0%, #f5f5f5 100%)
 | 
					 | 
				
			||||||
	border solid 1px #e2e2e2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	&:hover
 | 
					 | 
				
			||||||
		background linear-gradient(to bottom, #f9f9f9 0%, #ececec 100%)
 | 
					 | 
				
			||||||
		border-color #dcdcdc
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	&:active
 | 
					 | 
				
			||||||
		background #ececec
 | 
					 | 
				
			||||||
		border-color #dcdcdc
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
</style>
 | 
					 | 
				
			||||||
@@ -15,7 +15,7 @@
 | 
				
			|||||||
			<a v-for="tag in recentHashtags.slice(0, 5)" @click="addTag(tag)" :title="$t('click-to-tagging')">#{{ tag }}</a>
 | 
								<a v-for="tag in recentHashtags.slice(0, 5)" @click="addTag(tag)" :title="$t('click-to-tagging')">#{{ tag }}</a>
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
		<div class="local-only" v-if="this.localOnly == true">{{ $t('local-only-message') }}</div>
 | 
							<div class="local-only" v-if="this.localOnly == true">{{ $t('local-only-message') }}</div>
 | 
				
			||||||
		<input v-show="useCw" v-model="cw" :placeholder="$t('annotations')">
 | 
							<input v-show="useCw" ref="cw" v-model="cw" :placeholder="$t('annotations')" v-autocomplete="'cw'">
 | 
				
			||||||
		<div class="textarea">
 | 
							<div class="textarea">
 | 
				
			||||||
			<textarea :class="{ with: (files.length != 0 || poll) }"
 | 
								<textarea :class="{ with: (files.length != 0 || poll) }"
 | 
				
			||||||
				ref="text" v-model="text" :disabled="posting"
 | 
									ref="text" v-model="text" :disabled="posting"
 | 
				
			||||||
@@ -384,14 +384,13 @@ export default Vue.extend({
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		addVisibleUser() {
 | 
							addVisibleUser() {
 | 
				
			||||||
			this.$input({
 | 
								this.$root.dialog({
 | 
				
			||||||
				title: this.$t('enter-username')
 | 
									title: this.$t('enter-username'),
 | 
				
			||||||
			}).then(acct => {
 | 
									user: true
 | 
				
			||||||
				if (acct.startsWith('@')) acct = acct.substr(1);
 | 
								}).then(({ canceled, result: user }) => {
 | 
				
			||||||
				this.$root.api('users/show', parseAcct(acct)).then(user => {
 | 
									if (canceled) return;
 | 
				
			||||||
				this.visibleUsers.push(user);
 | 
									this.visibleUsers.push(user);
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
			});
 | 
					 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		removeVisibleUser(user) {
 | 
							removeVisibleUser(user) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,10 +35,13 @@ export default Vue.extend({
 | 
				
			|||||||
	},
 | 
						},
 | 
				
			||||||
	methods: {
 | 
						methods: {
 | 
				
			||||||
		register() {
 | 
							register() {
 | 
				
			||||||
			this.$input({
 | 
								this.$root.dialog({
 | 
				
			||||||
				title: this.$t('enter-password'),
 | 
									title: this.$t('enter-password'),
 | 
				
			||||||
 | 
									input: {
 | 
				
			||||||
					type: 'password'
 | 
										type: 'password'
 | 
				
			||||||
			}).then(password => {
 | 
									}
 | 
				
			||||||
 | 
								}).then(({ canceled, result: password }) => {
 | 
				
			||||||
 | 
									if (canceled) return;
 | 
				
			||||||
				this.$root.api('i/2fa/register', {
 | 
									this.$root.api('i/2fa/register', {
 | 
				
			||||||
					password: password
 | 
										password: password
 | 
				
			||||||
				}).then(data => {
 | 
									}).then(data => {
 | 
				
			||||||
@@ -48,10 +51,13 @@ export default Vue.extend({
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		unregister() {
 | 
							unregister() {
 | 
				
			||||||
			this.$input({
 | 
								this.$root.dialog({
 | 
				
			||||||
				title: this.$t('enter-password'),
 | 
									title: this.$t('enter-password'),
 | 
				
			||||||
 | 
									input: {
 | 
				
			||||||
					type: 'password'
 | 
										type: 'password'
 | 
				
			||||||
			}).then(password => {
 | 
									}
 | 
				
			||||||
 | 
								}).then(({ canceled, result: password }) => {
 | 
				
			||||||
 | 
									if (canceled) return;
 | 
				
			||||||
				this.$root.api('i/2fa/unregister', {
 | 
									this.$root.api('i/2fa/unregister', {
 | 
				
			||||||
					password: password
 | 
										password: password
 | 
				
			||||||
				}).then(() => {
 | 
									}).then(() => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -596,12 +596,12 @@ export default Vue.extend({
 | 
				
			|||||||
				this.checkingForUpdate = false;
 | 
									this.checkingForUpdate = false;
 | 
				
			||||||
				this.latestVersion = newer;
 | 
									this.latestVersion = newer;
 | 
				
			||||||
				if (newer == null) {
 | 
									if (newer == null) {
 | 
				
			||||||
					this.$root.alert({
 | 
										this.$root.dialog({
 | 
				
			||||||
						title: this.$t('no-updates'),
 | 
											title: this.$t('no-updates'),
 | 
				
			||||||
						text: this.$t('no-updates-desc')
 | 
											text: this.$t('no-updates-desc')
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					this.$root.alert({
 | 
										this.$root.dialog({
 | 
				
			||||||
						title: this.$t('update-available'),
 | 
											title: this.$t('update-available'),
 | 
				
			||||||
						text: this.$t('update-available-desc')
 | 
											text: this.$t('update-available-desc')
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
@@ -610,7 +610,7 @@ export default Vue.extend({
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		clean() {
 | 
							clean() {
 | 
				
			||||||
			localStorage.clear();
 | 
								localStorage.clear();
 | 
				
			||||||
			this.$root.alert({
 | 
								this.$root.dialog({
 | 
				
			||||||
				title: this.$t('cache-cleared'),
 | 
									title: this.$t('cache-cleared'),
 | 
				
			||||||
				text: this.$t('cache-cleared-desc')
 | 
									text: this.$t('cache-cleared-desc')
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -109,9 +109,11 @@ export default Vue.extend({
 | 
				
			|||||||
				icon: 'plus',
 | 
									icon: 'plus',
 | 
				
			||||||
				text: this.$t('add-list'),
 | 
									text: this.$t('add-list'),
 | 
				
			||||||
				action: () => {
 | 
									action: () => {
 | 
				
			||||||
					this.$input({
 | 
										this.$root.dialog({
 | 
				
			||||||
						title: this.$t('list-name'),
 | 
											title: this.$t('list-name'),
 | 
				
			||||||
					}).then(async title => {
 | 
											input: true
 | 
				
			||||||
 | 
										}).then(async ({ canceled, result: title }) => {
 | 
				
			||||||
 | 
											if (canceled) return;
 | 
				
			||||||
						const list = await this.$root.api('users/lists/create', {
 | 
											const list = await this.$root.api('users/lists/create', {
 | 
				
			||||||
							title
 | 
												title
 | 
				
			||||||
						});
 | 
											});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,9 +29,11 @@ export default Vue.extend({
 | 
				
			|||||||
	},
 | 
						},
 | 
				
			||||||
	methods: {
 | 
						methods: {
 | 
				
			||||||
		add() {
 | 
							add() {
 | 
				
			||||||
			this.$input({
 | 
								this.$root.dialog({
 | 
				
			||||||
				title: this.$t('list-name'),
 | 
									title: this.$t('list-name'),
 | 
				
			||||||
			}).then(async title => {
 | 
									input: true
 | 
				
			||||||
 | 
								}).then(async ({ canceled, result: title }) => {
 | 
				
			||||||
 | 
									if (canceled) return;
 | 
				
			||||||
				const list = await this.$root.api('users/lists/create', {
 | 
									const list = await this.$root.api('users/lists/create', {
 | 
				
			||||||
					title
 | 
										title
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -156,7 +156,7 @@ export default Vue.extend({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	> .follow-button
 | 
						> .follow-button
 | 
				
			||||||
		position absolute
 | 
							position absolute
 | 
				
			||||||
		top 92px
 | 
							top 8px
 | 
				
			||||||
		right 8px
 | 
							right 8px
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -167,11 +167,14 @@ export default Vue.extend({
 | 
				
			|||||||
				icon: 'pencil-alt',
 | 
									icon: 'pencil-alt',
 | 
				
			||||||
				text: this.$t('rename'),
 | 
									text: this.$t('rename'),
 | 
				
			||||||
				action: () => {
 | 
									action: () => {
 | 
				
			||||||
					this.$input({
 | 
										this.$root.dialog({
 | 
				
			||||||
						title: this.$t('rename'),
 | 
											title: this.$t('rename'),
 | 
				
			||||||
 | 
											input: {
 | 
				
			||||||
							default: this.name,
 | 
												default: this.name,
 | 
				
			||||||
							allowEmpty: false
 | 
												allowEmpty: false
 | 
				
			||||||
					}).then(name => {
 | 
											}
 | 
				
			||||||
 | 
										}).then(({ canceled, result: name }) => {
 | 
				
			||||||
 | 
											if (canceled) return;
 | 
				
			||||||
						this.$store.dispatch('settings/renameDeckColumn', { id: this.column.id, name });
 | 
											this.$store.dispatch('settings/renameDeckColumn', { id: this.column.id, name });
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -307,7 +307,7 @@ export default Vue.extend({
 | 
				
			|||||||
							listId: list.id,
 | 
												listId: list.id,
 | 
				
			||||||
							userId: this.user.id
 | 
												userId: this.user.id
 | 
				
			||||||
						});
 | 
											});
 | 
				
			||||||
						this.$root.alert({
 | 
											this.$root.dialog({
 | 
				
			||||||
							type: 'success',
 | 
												type: 'success',
 | 
				
			||||||
							splash: true
 | 
												splash: true
 | 
				
			||||||
						});
 | 
											});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -252,9 +252,11 @@ export default Vue.extend({
 | 
				
			|||||||
					icon: 'hashtag',
 | 
										icon: 'hashtag',
 | 
				
			||||||
					text: this.$t('@deck.hashtag'),
 | 
										text: this.$t('@deck.hashtag'),
 | 
				
			||||||
					action: () => {
 | 
										action: () => {
 | 
				
			||||||
						this.$input({
 | 
											this.$root.dialog({
 | 
				
			||||||
							title: this.$t('enter-hashtag-tl-title')
 | 
												title: this.$t('enter-hashtag-tl-title'),
 | 
				
			||||||
						}).then(title => {
 | 
												input: true
 | 
				
			||||||
 | 
											}).then(({ canceled, result: title }) => {
 | 
				
			||||||
 | 
												if (canceled) return;
 | 
				
			||||||
							this.$store.dispatch('settings/addDeckColumn', {
 | 
												this.$store.dispatch('settings/addDeckColumn', {
 | 
				
			||||||
								id: uuid(),
 | 
													id: uuid(),
 | 
				
			||||||
								type: 'hashtag',
 | 
													type: 'hashtag',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,12 +73,12 @@ export default Vue.extend({
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		block() {
 | 
							block() {
 | 
				
			||||||
			this.$root.alert({
 | 
								this.$root.dialog({
 | 
				
			||||||
				type: 'warning',
 | 
									type: 'warning',
 | 
				
			||||||
				text: this.$t('block-confirm'),
 | 
									text: this.$t('block-confirm'),
 | 
				
			||||||
				showCancelButton: true
 | 
									showCancelButton: true
 | 
				
			||||||
			}).then(res => {
 | 
								}).then(({ canceled }) => {
 | 
				
			||||||
				if (!res) return;
 | 
									if (canceled) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				this.$root.api('blocking/create', {
 | 
									this.$root.api('blocking/create', {
 | 
				
			||||||
					userId: this.user.id
 | 
										userId: this.user.id
 | 
				
			||||||
@@ -108,9 +108,13 @@ export default Vue.extend({
 | 
				
			|||||||
					listId: list.id,
 | 
										listId: list.id,
 | 
				
			||||||
					userId: this.user.id
 | 
										userId: this.user.id
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
				this.$root.alert({
 | 
									this.$root.dialog({
 | 
				
			||||||
 | 
										type: 'success',
 | 
				
			||||||
					title: 'Done!',
 | 
										title: 'Done!',
 | 
				
			||||||
					text: this.$t('list-pushed').replace('{user}', this.user.name).replace('{list}', list.title)
 | 
										text: this.$t('list-pushed', {
 | 
				
			||||||
 | 
											user: this.user.name,
 | 
				
			||||||
 | 
											list: list.title
 | 
				
			||||||
 | 
										})
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ import checkForUpdate from './common/scripts/check-for-update';
 | 
				
			|||||||
import MiOS from './mios';
 | 
					import MiOS from './mios';
 | 
				
			||||||
import { clientVersion as version, codename, lang } from './config';
 | 
					import { clientVersion as version, codename, lang } from './config';
 | 
				
			||||||
import { builtinThemes, lightTheme, applyTheme } from './theme';
 | 
					import { builtinThemes, lightTheme, applyTheme } from './theme';
 | 
				
			||||||
import Alert from './common/views/components/alert.vue';
 | 
					import Dialog from './common/views/components/dialog.vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (localStorage.getItem('theme') == null) {
 | 
					if (localStorage.getItem('theme') == null) {
 | 
				
			||||||
	applyTheme(lightTheme);
 | 
						applyTheme(lightTheme);
 | 
				
			||||||
@@ -457,11 +457,11 @@ export default (callback: (launch: (router: VueRouter) => [Vue, MiOS]) => void,
 | 
				
			|||||||
						document.body.appendChild(x.$el);
 | 
											document.body.appendChild(x.$el);
 | 
				
			||||||
						return x;
 | 
											return x;
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
					alert(opts) {
 | 
										dialog(opts) {
 | 
				
			||||||
						return new Promise((res) => {
 | 
											return new Promise((res) => {
 | 
				
			||||||
							const vm = this.new(Alert, opts);
 | 
												const vm = this.new(Dialog, opts);
 | 
				
			||||||
							vm.$once('ok', () => res(true));
 | 
												vm.$once('ok', result => res({ canceled: false, result }));
 | 
				
			||||||
							vm.$once('cancel', () => res(false));
 | 
												vm.$once('cancel', () => res({ canceled: true }));
 | 
				
			||||||
						});
 | 
											});
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,6 +41,12 @@ import FolderChooser from './views/components/drive-folder-chooser.vue';
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
init((launch) => {
 | 
					init((launch) => {
 | 
				
			||||||
	Vue.mixin({
 | 
						Vue.mixin({
 | 
				
			||||||
 | 
							data() {
 | 
				
			||||||
 | 
								return {
 | 
				
			||||||
 | 
									isMobile: true
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		methods: {
 | 
							methods: {
 | 
				
			||||||
			$post(opts) {
 | 
								$post(opts) {
 | 
				
			||||||
				const o = opts || {};
 | 
									const o = opts || {};
 | 
				
			||||||
@@ -89,15 +95,6 @@ init((launch) => {
 | 
				
			|||||||
				});
 | 
									});
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			$input(opts) {
 | 
					 | 
				
			||||||
				return new Promise<string>((res, rej) => {
 | 
					 | 
				
			||||||
					const x = window.prompt(opts.title);
 | 
					 | 
				
			||||||
					if (x) {
 | 
					 | 
				
			||||||
						res(x);
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				});
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			$notify(message) {
 | 
								$notify(message) {
 | 
				
			||||||
				alert(message);
 | 
									alert(message);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,7 +16,7 @@
 | 
				
			|||||||
				<span v-for="u in visibleUsers">{{ u | userName }}<a @click="removeVisibleUser(u)">[x]</a></span>
 | 
									<span v-for="u in visibleUsers">{{ u | userName }}<a @click="removeVisibleUser(u)">[x]</a></span>
 | 
				
			||||||
				<a @click="addVisibleUser">+{{ $t('add-visible-user') }}</a>
 | 
									<a @click="addVisibleUser">+{{ $t('add-visible-user') }}</a>
 | 
				
			||||||
			</div>
 | 
								</div>
 | 
				
			||||||
			<input v-show="useCw" v-model="cw" :placeholder="$t('annotations')">
 | 
								<input v-show="useCw" ref="cw" v-model="cw" :placeholder="$t('annotations')" v-autocomplete="'cw'">
 | 
				
			||||||
			<textarea v-model="text" ref="text" :disabled="posting" :placeholder="placeholder" v-autocomplete="'text'"></textarea>
 | 
								<textarea v-model="text" ref="text" :disabled="posting" :placeholder="placeholder" v-autocomplete="'text'"></textarea>
 | 
				
			||||||
			<div class="attaches" v-show="files.length != 0">
 | 
								<div class="attaches" v-show="files.length != 0">
 | 
				
			||||||
				<x-draggable class="files" :list="files" :options="{ animation: 150 }">
 | 
									<x-draggable class="files" :list="files" :options="{ animation: 150 }">
 | 
				
			||||||
@@ -219,6 +219,16 @@ export default Vue.extend({
 | 
				
			|||||||
			(this.$refs.text as any).focus();
 | 
								(this.$refs.text as any).focus();
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							addVisibleUser() {
 | 
				
			||||||
 | 
								this.$root.dialog({
 | 
				
			||||||
 | 
									title: this.$t('enter-username'),
 | 
				
			||||||
 | 
									user: true
 | 
				
			||||||
 | 
								}).then(({ canceled, result: user }) => {
 | 
				
			||||||
 | 
									if (canceled) return;
 | 
				
			||||||
 | 
									this.visibleUsers.push(user);
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		chooseFile() {
 | 
							chooseFile() {
 | 
				
			||||||
			(this.$refs.file as any).click();
 | 
								(this.$refs.file as any).click();
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,12 +23,12 @@ export default Vue.extend({
 | 
				
			|||||||
	},
 | 
						},
 | 
				
			||||||
	methods: {
 | 
						methods: {
 | 
				
			||||||
		fn() {
 | 
							fn() {
 | 
				
			||||||
			this.$root.alert({
 | 
								this.$root.dialog({
 | 
				
			||||||
				type: 'warning',
 | 
									type: 'warning',
 | 
				
			||||||
				text: this.$t('read-all'),
 | 
									text: this.$t('read-all'),
 | 
				
			||||||
				showCancelButton: true
 | 
									showCancelButton: true
 | 
				
			||||||
			}).then(res => {
 | 
								}).then(({ canceled }) => {
 | 
				
			||||||
				if (!res) return;
 | 
									if (canceled) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				this.$root.api('notifications/mark_all_as_read');
 | 
									this.$root.api('notifications/mark_all_as_read');
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -402,12 +402,12 @@ export default Vue.extend({
 | 
				
			|||||||
				this.checkingForUpdate = false;
 | 
									this.checkingForUpdate = false;
 | 
				
			||||||
				this.latestVersion = newer;
 | 
									this.latestVersion = newer;
 | 
				
			||||||
				if (newer == null) {
 | 
									if (newer == null) {
 | 
				
			||||||
					this.$root.alert({
 | 
										this.$root.dialog({
 | 
				
			||||||
						title: this.$t('no-updates'),
 | 
											title: this.$t('no-updates'),
 | 
				
			||||||
						text: this.$t('no-updates-desc')
 | 
											text: this.$t('no-updates-desc')
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					this.$root.alert({
 | 
										this.$root.dialog({
 | 
				
			||||||
						title: this.$t('update-available'),
 | 
											title: this.$t('update-available'),
 | 
				
			||||||
						text: this.$t('update-available-desc')
 | 
											text: this.$t('update-available-desc')
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,9 +38,11 @@ export default Vue.extend({
 | 
				
			|||||||
	},
 | 
						},
 | 
				
			||||||
	methods: {
 | 
						methods: {
 | 
				
			||||||
		fn() {
 | 
							fn() {
 | 
				
			||||||
			this.$input({
 | 
								this.$root.dialog({
 | 
				
			||||||
				title: this.$t('enter-list-name'),
 | 
									title: this.$t('enter-list-name'),
 | 
				
			||||||
			}).then(async title => {
 | 
									input: true
 | 
				
			||||||
 | 
								}).then(async ({ canceled, result: title }) => {
 | 
				
			||||||
 | 
									if (canceled) return;
 | 
				
			||||||
				const list = await this.$root.api('users/lists/create', {
 | 
									const list = await this.$root.api('users/lists/create', {
 | 
				
			||||||
					title
 | 
										title
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -116,6 +116,34 @@ export default Vue.extend({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		menu() {
 | 
							menu() {
 | 
				
			||||||
			let menu = [{
 | 
								let menu = [{
 | 
				
			||||||
 | 
									icon: ['fas', 'list'],
 | 
				
			||||||
 | 
									text: this.$t('push-to-list'),
 | 
				
			||||||
 | 
									action: async () => {
 | 
				
			||||||
 | 
										const lists = await this.$root.api('users/lists/list');
 | 
				
			||||||
 | 
										const { canceled, result: listId } = await this.$root.dialog({
 | 
				
			||||||
 | 
											type: null,
 | 
				
			||||||
 | 
											title: this.$t('select-list'),
 | 
				
			||||||
 | 
											select: {
 | 
				
			||||||
 | 
												items: lists.map(list => ({
 | 
				
			||||||
 | 
													value: list.id, text: list.title
 | 
				
			||||||
 | 
												}))
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											showCancelButton: true
 | 
				
			||||||
 | 
										});
 | 
				
			||||||
 | 
										if (canceled) return;
 | 
				
			||||||
 | 
										await this.$root.api('users/lists/push', {
 | 
				
			||||||
 | 
											listId: listId,
 | 
				
			||||||
 | 
											userId: this.user.id
 | 
				
			||||||
 | 
										});
 | 
				
			||||||
 | 
										this.$root.dialog({
 | 
				
			||||||
 | 
											type: 'success',
 | 
				
			||||||
 | 
											text: this.$t('list-pushed', {
 | 
				
			||||||
 | 
												user: this.user.name,
 | 
				
			||||||
 | 
												list: lists.find(l => l.id === listId).title
 | 
				
			||||||
 | 
											})
 | 
				
			||||||
 | 
										});
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}, null, {
 | 
				
			||||||
				icon: this.user.isMuted ? ['fas', 'eye'] : ['far', 'eye-slash'],
 | 
									icon: this.user.isMuted ? ['fas', 'eye'] : ['far', 'eye-slash'],
 | 
				
			||||||
				text: this.user.isMuted ? this.$t('unmute') : this.$t('mute'),
 | 
									text: this.user.isMuted ? this.$t('unmute') : this.$t('mute'),
 | 
				
			||||||
				action: () => {
 | 
									action: () => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -63,7 +63,7 @@ export default Vue.extend({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	methods: {
 | 
						methods: {
 | 
				
			||||||
		showDialog() {
 | 
							showDialog() {
 | 
				
			||||||
			this.$root.alert({
 | 
								this.$root.dialog({
 | 
				
			||||||
				type: this.dialogType,
 | 
									type: this.dialogType,
 | 
				
			||||||
				title: this.dialogTitle,
 | 
									title: this.dialogTitle,
 | 
				
			||||||
				text: this.dialogText,
 | 
									text: this.dialogText,
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -48,7 +48,7 @@ export interface INotification {
 | 
				
			|||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * 通知が読まれたかどうか
 | 
						 * 通知が読まれたかどうか
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	isRead: Boolean;
 | 
						isRead: boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const packMany = (
 | 
					export const packMany = (
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,3 +57,15 @@ export function lessThan(xs: number[], ys: number[]): boolean {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return xs.length < ys.length;
 | 
						return xs.length < ys.length;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function takeWhile<T>(f: (x: T) => boolean, xs: T[]): T[] {
 | 
				
			||||||
 | 
						const ys = [];
 | 
				
			||||||
 | 
						for (const x of xs) {
 | 
				
			||||||
 | 
							if (f(x)) {
 | 
				
			||||||
 | 
								ys.push(x);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ys;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@ import { resolvePerson, updatePerson } from './person';
 | 
				
			|||||||
import { resolveImage } from './image';
 | 
					import { resolveImage } from './image';
 | 
				
			||||||
import { IRemoteUser, IUser } from '../../../models/user';
 | 
					import { IRemoteUser, IUser } from '../../../models/user';
 | 
				
			||||||
import htmlToMFM from '../../../mfm/html-to-mfm';
 | 
					import htmlToMFM from '../../../mfm/html-to-mfm';
 | 
				
			||||||
import Emoji from '../../../models/emoji';
 | 
					import Emoji, { IEmoji } from '../../../models/emoji';
 | 
				
			||||||
import { ITag } from './tag';
 | 
					import { ITag } from './tag';
 | 
				
			||||||
import { toUnicode } from 'punycode';
 | 
					import { toUnicode } from 'punycode';
 | 
				
			||||||
import { unique, concat, difference } from '../../../prelude/array';
 | 
					import { unique, concat, difference } from '../../../prelude/array';
 | 
				
			||||||
@@ -84,6 +84,8 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	const apMentions = await extractMentionedUsers(actor, note.to, note.cc, resolver);
 | 
						const apMentions = await extractMentionedUsers(actor, note.to, note.cc, resolver);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const apHashtags = await extractHashtags(note.tag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 添付ファイル
 | 
						// 添付ファイル
 | 
				
			||||||
	// TODO: attachmentは必ずしもImageではない
 | 
						// TODO: attachmentは必ずしもImageではない
 | 
				
			||||||
	// TODO: attachmentは必ずしも配列ではない
 | 
						// TODO: attachmentは必ずしも配列ではない
 | 
				
			||||||
@@ -108,10 +110,13 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
 | 
				
			|||||||
	// テキストのパース
 | 
						// テキストのパース
 | 
				
			||||||
	const text = note._misskey_content ? note._misskey_content : htmlToMFM(note.content);
 | 
						const text = note._misskey_content ? note._misskey_content : htmlToMFM(note.content);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	await extractEmojis(note.tag, actor.host).catch(e => {
 | 
						const emojis = await extractEmojis(note.tag, actor.host).catch(e => {
 | 
				
			||||||
		console.log(`extractEmojis: ${e}`);
 | 
							console.log(`extractEmojis: ${e}`);
 | 
				
			||||||
 | 
							return [] as IEmoji[];
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const apEmojis = emojis.map(emoji => emoji.name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ユーザーの情報が古かったらついでに更新しておく
 | 
						// ユーザーの情報が古かったらついでに更新しておく
 | 
				
			||||||
	if (actor.lastFetchedAt == null || Date.now() - actor.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
 | 
						if (actor.lastFetchedAt == null || Date.now() - actor.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) {
 | 
				
			||||||
		updatePerson(note.attributedTo);
 | 
							updatePerson(note.attributedTo);
 | 
				
			||||||
@@ -130,6 +135,8 @@ export async function createNote(value: any, resolver?: Resolver, silent = false
 | 
				
			|||||||
		visibility,
 | 
							visibility,
 | 
				
			||||||
		visibleUsers,
 | 
							visibleUsers,
 | 
				
			||||||
		apMentions,
 | 
							apMentions,
 | 
				
			||||||
 | 
							apHashtags,
 | 
				
			||||||
 | 
							apEmojis,
 | 
				
			||||||
		uri: note.id
 | 
							uri: note.id
 | 
				
			||||||
	}, silent);
 | 
						}, silent);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -199,3 +206,14 @@ async function extractMentionedUsers(actor: IRemoteUser, to: string[], cc: strin
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return users.filter(x => x != null);
 | 
						return users.filter(x => x != null);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function extractHashtags(tags: ITag[]) {
 | 
				
			||||||
 | 
						if (!tags) return [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const hashtags = tags.filter(tag => tag.type === 'Hashtag' && typeof tag.name == 'string');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return hashtags.map(tag => {
 | 
				
			||||||
 | 
							const m = tag.name.match(/^#(.+)/);
 | 
				
			||||||
 | 
							return m ? m[1] : null;
 | 
				
			||||||
 | 
						}).filter(x => x != null);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -164,7 +164,7 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<IU
 | 
				
			|||||||
			uri: person.id,
 | 
								uri: person.id,
 | 
				
			||||||
			url: person.url,
 | 
								url: person.url,
 | 
				
			||||||
			isBot: isBot,
 | 
								isBot: isBot,
 | 
				
			||||||
			isCat: (person as any).isCat === true ? true : false
 | 
								isCat: (person as any).isCat === true
 | 
				
			||||||
		}) as IRemoteUser;
 | 
							}) as IRemoteUser;
 | 
				
			||||||
	} catch (e) {
 | 
						} catch (e) {
 | 
				
			||||||
		// duplicate key error
 | 
							// duplicate key error
 | 
				
			||||||
@@ -322,7 +322,7 @@ export async function updatePerson(uri: string, resolver?: Resolver, hint?: obje
 | 
				
			|||||||
			url: person.url,
 | 
								url: person.url,
 | 
				
			||||||
			endpoints: person.endpoints,
 | 
								endpoints: person.endpoints,
 | 
				
			||||||
			isBot: object.type == 'Service',
 | 
								isBot: object.type == 'Service',
 | 
				
			||||||
			isCat: (person as any).isCat === true ? true : false,
 | 
								isCat: (person as any).isCat === true
 | 
				
			||||||
			isLocked: person.manuallyApprovesFollowers,
 | 
								isLocked: person.manuallyApprovesFollowers,
 | 
				
			||||||
			createdAt: Date.parse(person.published) || null,
 | 
								createdAt: Date.parse(person.published) || null,
 | 
				
			||||||
			publicKey: {
 | 
								publicKey: {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -63,7 +63,7 @@ export default define(meta, (ps) => new Promise(async (res, rej) => {
 | 
				
			|||||||
	});
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// タグを人気順に並べ替え
 | 
						// タグを人気順に並べ替え
 | 
				
			||||||
	tags = tags.sort((a, b) => b.count - a.count);
 | 
						tags.sort((a, b) => b.count - a.count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tags = tags.slice(0, 30);
 | 
						tags = tags.slice(0, 30);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -106,9 +106,7 @@ export default define(meta, (ps) => new Promise(async (res, rej) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	const withFiles = ps.withFiles != undefined ? ps.withFiles : ps.media;
 | 
						const withFiles = ps.withFiles != undefined ? ps.withFiles : ps.media;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (withFiles) {
 | 
						if (withFiles) query.fileIds = { $exists: true, $ne: null };
 | 
				
			||||||
		query.fileIds = withFiles ? { $exists: true, $ne: null } : [];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ps.poll != undefined) {
 | 
						if (ps.poll != undefined) {
 | 
				
			||||||
		query.poll = ps.poll ? { $exists: true, $ne: null } : null;
 | 
							query.poll = ps.poll ? { $exists: true, $ne: null } : null;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,7 +30,7 @@ async function genVars(lang: string): Promise<{ [key: string]: any }> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	const entities = glob.sync('src/docs/api/entities/**/*.yaml', { cwd });
 | 
						const entities = glob.sync('src/docs/api/entities/**/*.yaml', { cwd });
 | 
				
			||||||
	vars['entities'] = entities.map(x => {
 | 
						vars['entities'] = entities.map(x => {
 | 
				
			||||||
		const _x = yaml.safeLoad(fs.readFileSync(cwd + x, 'utf-8')) as any;
 | 
							const _x = yaml.safeLoad(fs.readFileSync(cwd + x, 'utf-8'));
 | 
				
			||||||
		return _x.name;
 | 
							return _x.name;
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -197,7 +197,7 @@ router.get('/*/api/entities/*', async ctx => {
 | 
				
			|||||||
	const lang = ctx.params[0];
 | 
						const lang = ctx.params[0];
 | 
				
			||||||
	const entity = ctx.params[1];
 | 
						const entity = ctx.params[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const x = yaml.safeLoad(fs.readFileSync(path.resolve(`${__dirname}/../../../src/docs/api/entities/${entity}.yaml`), 'utf-8')) as any;
 | 
						const x = yaml.safeLoad(fs.readFileSync(path.resolve(`${__dirname}/../../../src/docs/api/entities/${entity}.yaml`), 'utf-8'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	await ctx.render('../../../../src/docs/api/entities/view', Object.assign(await genVars(lang), {
 | 
						await ctx.render('../../../../src/docs/api/entities/view', Object.assign(await genVars(lang), {
 | 
				
			||||||
		id: `api/entities/${entity}`,
 | 
							id: `api/entities/${entity}`,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -98,6 +98,8 @@ type Option = {
 | 
				
			|||||||
	visibility?: string;
 | 
						visibility?: string;
 | 
				
			||||||
	visibleUsers?: IUser[];
 | 
						visibleUsers?: IUser[];
 | 
				
			||||||
	apMentions?: IUser[];
 | 
						apMentions?: IUser[];
 | 
				
			||||||
 | 
						apHashtags?: string[];
 | 
				
			||||||
 | 
						apEmojis?: string[];
 | 
				
			||||||
	uri?: string;
 | 
						uri?: string;
 | 
				
			||||||
	app?: IApp;
 | 
						app?: IApp;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -153,16 +155,22 @@ export default async (user: IUser, data: Option, silent = false) => new Promise<
 | 
				
			|||||||
		data.text = data.text.trim();
 | 
							data.text = data.text.trim();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Parse MFM
 | 
						let tags = data.apHashtags;
 | 
				
			||||||
 | 
						let emojis = data.apEmojis;
 | 
				
			||||||
 | 
						let mentionedUsers = data.apMentions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Parse MFM if needed
 | 
				
			||||||
 | 
						if (!tags || !emojis || !mentionedUsers) {
 | 
				
			||||||
		const tokens = data.text ? parse(data.text) : [];
 | 
							const tokens = data.text ? parse(data.text) : [];
 | 
				
			||||||
		const cwTokens = data.cw ? parse(data.cw) : [];
 | 
							const cwTokens = data.cw ? parse(data.cw) : [];
 | 
				
			||||||
		const combinedTokens = tokens.concat(cwTokens);
 | 
							const combinedTokens = tokens.concat(cwTokens);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const tags = extractHashtags(combinedTokens);
 | 
							tags = data.apHashtags || extractHashtags(combinedTokens);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const emojis = extractEmojis(combinedTokens);
 | 
							emojis = data.apEmojis || extractEmojis(combinedTokens);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const mentionedUsers = data.apMentions || await extractMentionedUsers(user, combinedTokens);
 | 
							mentionedUsers = data.apMentions || await extractMentionedUsers(user, combinedTokens);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (data.reply && !user._id.equals(data.reply.userId) && !mentionedUsers.some(u => u._id.equals(data.reply.userId))) {
 | 
						if (data.reply && !user._id.equals(data.reply.userId) && !mentionedUsers.some(u => u._id.equals(data.reply.userId))) {
 | 
				
			||||||
		mentionedUsers.push(await User.findOne({ _id: data.reply.userId }));
 | 
							mentionedUsers.push(await User.findOne({ _id: data.reply.userId }));
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user