summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md11
-rw-r--r--locales/de-DE.yml9
-rw-r--r--locales/en-US.yml9
-rw-r--r--locales/es-ES.yml9
-rw-r--r--locales/ja-JP.yml7
-rw-r--r--locales/ja-KS.yml49
-rw-r--r--locales/lo-LA.yml82
-rw-r--r--locales/th-TH.yml5
-rw-r--r--locales/zh-CN.yml12
-rw-r--r--locales/zh-TW.yml8
-rw-r--r--package.json4
-rw-r--r--packages/backend/src/server/FileServerService.ts24
-rw-r--r--packages/frontend/src/components/MkAchievements.vue1
-rw-r--r--packages/frontend/src/components/MkCwButton.vue2
-rw-r--r--packages/frontend/src/components/MkDialog.vue6
-rw-r--r--packages/frontend/src/components/MkMediaBanner.vue4
-rw-r--r--packages/frontend/src/components/MkSignup.vue12
-rw-r--r--packages/frontend/src/components/global/MkAvatar.vue39
-rw-r--r--packages/frontend/src/os.ts2
-rw-r--r--packages/frontend/src/pages/auth.form.vue108
-rw-r--r--packages/frontend/src/pages/auth.vue170
-rw-r--r--packages/frontend/src/pages/miauth.vue79
-rw-r--r--packages/frontend/src/pages/settings/profile.vue4
-rw-r--r--packages/frontend/src/ui/_common_/navbar-for-mobile.vue13
-rw-r--r--packages/frontend/src/ui/_common_/navbar.vue13
25 files changed, 475 insertions, 207 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c9bda35348..6705535f00 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,17 @@
You should also include the user name that made the change.
-->
+## 13.5.6 (2023/02/10)
+
+### Improvements
+- 非ログイン時にMiAuthを踏んだ際にMiAuthであることを表示する
+- /auth/のUIをアップデート
+- 利用規約同意UIの調整
+- クロップ時の質問を分かりやすく
+
+### Bugfixes
+- fix: prevent clipping audio plyr's tooltip
+
## 13.5.4 (2023/02/09)
### Improvements
diff --git a/locales/de-DE.yml b/locales/de-DE.yml
index 85c7a3e63f..c1b272b26d 100644
--- a/locales/de-DE.yml
+++ b/locales/de-DE.yml
@@ -257,6 +257,8 @@ noMoreHistory: "Kein weiterer Verlauf vorhanden"
startMessaging: "Neuen Chat erstellen"
nUsersRead: "Von {n} Benutzern gelesen"
agreeTo: "Ich stimme {0} zu"
+agreeBelow: "Ich stimme Untenstehendem zu"
+basicNotesBeforeCreateAccount: "Wichtige Infos"
tos: "Nutzungsbedingungen"
start: "Anfangen"
home: "Startseite"
@@ -862,6 +864,8 @@ failedToFetchAccountInformation: "Benutzerkontoinformationen konnten nicht abgef
rateLimitExceeded: "Versuchsanzahl überschritten"
cropImage: "Bild zuschneiden"
cropImageAsk: "Möchtest du das Bild zuschneiden?"
+cropYes: "Zuschneiden"
+cropNo: "Unbearbeitet verwenden"
file: "Datei"
recentNHours: "Letzten {n} Stunden"
recentNDays: "Letzten {n} Tage"
@@ -940,6 +944,8 @@ cannotPerformTemporaryDescription: "Diese Aktion ist wegen des Überschreitenes
preset: "Vorlage"
selectFromPresets: "Aus Vorlagen wählen"
achievements: "Errungenschaften"
+gotInvalidResponseError: "Ungültige Antwort des Servers"
+gotInvalidResponseErrorDescription: "Eventuell ist der Server momentan nicht erreichbar oder untergeht Wartungsarbeiten. Bitte versuche es später noch einmal."
_achievements:
earnedAt: "Freigeschaltet am"
_types:
@@ -1594,12 +1600,15 @@ _permissions:
"read:gallery-likes": "Liste deiner mit \"Gefällt mir\" markierten Galerie-Beiträge lesen"
"write:gallery-likes": "Liste deiner mit \"Gefällt mir\" markierten Galerie-Beiträge bearbeiten"
_auth:
+ shareAccessTitle: "Verteilung von App-Berechtigungen"
shareAccess: "Möchtest du „{name}“ authorisieren, auf dieses Benutzerkonto zugreifen zu können?"
shareAccessAsk: "Bist du dir sicher, dass du diese Anwendung authorisieren möchtest, auf dein Benutzerkonto zugreifen zu können?"
+ permission: "{name} fordert folgende Berechtigungen"
permissionAsk: "Diese Anwendung fordert folgende Berechtigungen"
pleaseGoBack: "Bitte kehre zur Anwendung zurück"
callback: "Es wird zur Anwendung zurückgekehrt"
denied: "Zugriff verweigert"
+ pleaseLogin: "Bitte logge dich ein, um Apps zu authorisieren."
_antennaSources:
all: "Alle Notizen"
homeTimeline: "Notizen von Benutzern, denen gefolgt wird"
diff --git a/locales/en-US.yml b/locales/en-US.yml
index d9a34b8999..685e373a43 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -257,6 +257,8 @@ noMoreHistory: "There is no further history"
startMessaging: "Start a new chat"
nUsersRead: "read by {n}"
agreeTo: "I agree to {0}"
+agreeBelow: "I agree to the below"
+basicNotesBeforeCreateAccount: "Important notes"
tos: "Terms of Service"
start: "Begin"
home: "Home"
@@ -862,6 +864,8 @@ failedToFetchAccountInformation: "Could not fetch account information"
rateLimitExceeded: "Rate limit exceeded"
cropImage: "Crop image"
cropImageAsk: "Do you want to crop this image?"
+cropYes: "Crop"
+cropNo: "Use as-is"
file: "File"
recentNHours: "Last {n} hours"
recentNDays: "Last {n} days"
@@ -940,6 +944,8 @@ cannotPerformTemporaryDescription: "This action cannot be performed temporarily
preset: "Preset"
selectFromPresets: "Choose from presets"
achievements: "Achievements"
+gotInvalidResponseError: "Invalid server response"
+gotInvalidResponseErrorDescription: "The server may be unreachable or undergoing maintenance. Please try again later."
_achievements:
earnedAt: "Unlocked at"
_types:
@@ -1594,12 +1600,15 @@ _permissions:
"read:gallery-likes": "View your list of liked gallery posts"
"write:gallery-likes": "Edit your list of liked gallery posts"
_auth:
+ shareAccessTitle: "Granting application permissions"
shareAccess: "Would you like to authorize \"{name}\" to access this account?"
shareAccessAsk: "Are you sure you want to authorize this application to access your account?"
+ permission: "{name} requests the following permissions"
permissionAsk: "This application requests the following permissions"
pleaseGoBack: "Please go back to the application"
callback: "Returning to the application"
denied: "Access denied"
+ pleaseLogin: "Please log in to authorize applications."
_antennaSources:
all: "All notes"
homeTimeline: "Notes from followed users"
diff --git a/locales/es-ES.yml b/locales/es-ES.yml
index f3cd85e6a0..5c1d249f67 100644
--- a/locales/es-ES.yml
+++ b/locales/es-ES.yml
@@ -56,7 +56,7 @@ reply: "Responder"
loadMore: "Ver más"
showMore: "Ver más"
showLess: "Cerrar"
-youGotNewFollower: "te ha seguido"
+youGotNewFollower: "ahora te sigue"
receiveFollowRequest: "Recibiste una solicitud de seguimiento"
followRequestAccepted: "La solicitud de seguimiento fue aceptada"
mention: "Menciones"
@@ -257,6 +257,8 @@ noMoreHistory: "El historial se ha acabado"
startMessaging: "Iniciar chat"
nUsersRead: "Leído por {n} personas"
agreeTo: "De acuerdo con {0}"
+agreeBelow: "Estoy de acuerdo con lo siguiente"
+basicNotesBeforeCreateAccount: "Notas básicas"
tos: "Términos de uso"
start: "Comenzar"
home: "Inicio"
@@ -940,6 +942,8 @@ cannotPerformTemporaryDescription: "Esta acción no se puede realizar porque se
preset: "Predefinido"
selectFromPresets: "Escoger desde predefinidos"
achievements: "Logros"
+gotInvalidResponseError: "Respuesta del servidor inválida"
+gotInvalidResponseErrorDescription: "Puede que el servidor esté caído o en mantenimiento. Favor de intentar más tarde"
_achievements:
earnedAt: "Desbloqueado el"
_types:
@@ -1594,12 +1598,15 @@ _permissions:
"read:gallery-likes": "Ver favoritos de la galería"
"write:gallery-likes": "Editar favoritos de la galería"
_auth:
+ shareAccessTitle: "Permisos de la aplicación"
shareAccess: "¿Desea permitir el acceso a la cuenta \"{name}\"?"
shareAccessAsk: "¿Está seguro de que desea autorizar esta aplicación para acceder a su cuenta?"
+ permission: "{name} solicita los siguientes permisos"
permissionAsk: "Esta aplicación requiere los siguientes permisos"
pleaseGoBack: "Por favor, vuelve a la aplicación"
callback: "Volviendo a la aplicación"
denied: "Acceso denegado"
+ pleaseLogin: "Se requiere un inicio de sesión para darle permisos a la aplicación"
_antennaSources:
all: "Todas las notas"
homeTimeline: "Notas de los usuarios que sigues"
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 09069e7801..79b78f3f98 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -257,6 +257,8 @@ noMoreHistory: "これより過去の履歴はありません"
startMessaging: "チャットを開始"
nUsersRead: "{n}人が読みました"
agreeTo: "{0}に同意"
+agreeBelow: "下記に同意する"
+basicNotesBeforeCreateAccount: "基本的な注意事項"
tos: "利用規約"
start: "始める"
home: "ホーム"
@@ -862,6 +864,8 @@ failedToFetchAccountInformation: "アカウント情報の取得に失敗しま
rateLimitExceeded: "レート制限を超えました"
cropImage: "画像のクロップ"
cropImageAsk: "画像をクロップしますか?"
+cropYes: "クロップする"
+cropNo: "そのまま使う"
file: "ファイル"
recentNHours: "直近{n}時間"
recentNDays: "直近{n}日"
@@ -1628,12 +1632,15 @@ _permissions:
"write:gallery-likes": "ギャラリーのいいねを操作する"
_auth:
+ shareAccessTitle: "アプリへのアクセス許可"
shareAccess: "「{name}」がアカウントにアクセスすることを許可しますか?"
shareAccessAsk: "アカウントへのアクセスを許可しますか?"
+ permission: "{name}は次の権限を要求しています"
permissionAsk: "このアプリは次の権限を要求しています"
pleaseGoBack: "アプリケーションに戻ってやっていってください"
callback: "アプリケーションに戻っています"
denied: "アクセスを拒否しました"
+ pleaseLogin: "アプリケーションにアクセス許可を与えるには、ログインが必要です。"
_antennaSources:
all: "全てのノート"
diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml
index 05de911bec..2987112e24 100644
--- a/locales/ja-KS.yml
+++ b/locales/ja-KS.yml
@@ -46,7 +46,7 @@ copyContent: "内容をコピー"
copyLink: "リンクをコピー"
delete: "ほかす"
deleteAndEdit: "ほかして直す"
-deleteAndEditConfirm: "このノートをほかして書き直すんか?このノートへのリアクション、Renote、返信も全部消えてまうで。"
+deleteAndEditConfirm: "このノートをほかしてもっかい直す?このノートへのリアクション、Renote、返信も全部消えるんやけどそれでもええん?"
addToList: "リストに入れたる"
sendMessage: "メッセージを送る"
copyRSS: "RSSをコピー"
@@ -89,7 +89,7 @@ serverIsDead: "サーバーからの応答がないで。もうちょい待っ
youShouldUpgradeClient: "このページを表示するには、リロードして新しいバージョンのクライアントを使ってなー。"
enterListName: "リスト名を入れてや"
privacy: "プライバシー"
-makeFollowManuallyApprove: "自分が認めた人だけがこのアカウントをフォローできるようにする"
+makeFollowManuallyApprove: "他人のフォローは許可してからや!"
defaultNoteVisibility: "もとからの公開範囲"
follow: "フォロー"
followRequest: "フォローを頼む"
@@ -129,6 +129,7 @@ unblockConfirm: "ブロックやめたるってほんまか?"
suspendConfirm: "凍結してしもうてええか?"
unsuspendConfirm: "解凍するけどええか?"
selectList: "リストを選ぶ"
+selectChannel: "チャンネルを選ぶ"
selectAntenna: "アンテナを選ぶ"
selectWidget: "ウィジェットを選ぶ"
editWidgets: "ウィジェットをいじる"
@@ -256,6 +257,8 @@ noMoreHistory: "これより過去の履歴はあらへんで"
startMessaging: "チャットやるで"
nUsersRead: "{n}人が読んでもうた"
agreeTo: "{0}に同意したで"
+agreeBelow: "下記に同意したる"
+basicNotesBeforeCreateAccount: "よう読んでやってや"
tos: "利用規約"
start: "始める"
home: "ホーム"
@@ -300,7 +303,7 @@ avatar: "アイコン"
banner: "バナー"
nsfw: "閲覧注意"
whenServerDisconnected: "サーバーとの接続が切れたとき"
-disconnectedFromServer: "サーバーとの通信が切れたで"
+disconnectedFromServer: "サーバーが機嫌悪いねん"
reload: "リロード"
doNothing: "何もせんとく"
reloadConfirm: "リロードしてええか?"
@@ -673,8 +676,8 @@ sentReactionsCount: "リアクションした数やで"
receivedReactionsCount: "リアクションされた数"
pollVotesCount: "アンケートに投票した数"
pollVotedCount: "アンケートに投票された数"
-yes: "はい"
-no: "いいえ"
+yes: "ええで"
+no: "あかんで"
driveFilesCount: "ドライブのファイル数"
driveUsage: "ドライブ使用量やで"
noCrawle: "クローラーによるインデックスを拒否するで"
@@ -861,6 +864,8 @@ failedToFetchAccountInformation: "アカウントの取得に失敗したみた
rateLimitExceeded: "レート制限が超えたみたいやで"
cropImage: "画像のクロップ"
cropImageAsk: "画像をクロップしたってええか?"
+cropYes: "切り抜いたる"
+cropNo: "切り抜かへん"
file: "ファイル"
recentNHours: "直近{n}時間"
recentNDays: "直近{n}日"
@@ -938,6 +943,37 @@ cannotPerformTemporary: "一時的に利用できへんで"
cannotPerformTemporaryDescription: "操作回数が制限を超えたから一時的に利用できへんくなったで。ちょっと時間置いてからもう一回やってやー。"
preset: "プリセット"
selectFromPresets: "プリセットから選ぶ"
+achievements: "実績"
+gotInvalidResponseError: "サーバー黙っとるわ、知らんけど"
+gotInvalidResponseErrorDescription: "サーバーいま日曜日。またきて月曜日。"
+_achievements:
+ earnedAt: "貰った日ぃ"
+ _types:
+ _notes1:
+ title: "まいど!"
+ description: "初めてノート投稿したった"
+ _notes10:
+ title: "ノートの天保山"
+ _notes100:
+ title: "ノートの真田山"
+ _notes500:
+ title: "ノートの生駒山"
+ _notes5000:
+ title: "箕面の滝からノート"
+ _login3:
+ flavor: "今日からワシはミスキストやで"
+ _iLoveMisskey:
+ title: "Misskey好きやねん"
+ _foundTreasure:
+ title: "なんでも鑑定団"
+ _client30min:
+ title: "ねんね"
+ _noteDeletedWithin1min:
+ title: "*おおっと*"
+ _open3windows:
+ title: "マド開けすぎ"
+ _driveFolderCircularReference:
+ title: "環状線"
_role:
new: "ロールの作成"
edit: "ロールの編集"
@@ -1355,10 +1391,12 @@ _permissions:
_auth:
shareAccess: "「{name}」がアカウントにアクセスすることを許可してええか?"
shareAccessAsk: "アカウントのアクセスを許可してもええか?"
+ permission: "{name}に次の権限つけたってやって"
permissionAsk: "このアプリは次の権限を要求しとるで"
pleaseGoBack: "アプリケーションに戻ってええよ"
callback: "アプリケーションに戻っとるで"
denied: "アクセスを拒否ったで"
+ pleaseLogin: "アプリにアクセスさせるんやったら、ログインしてや。"
_antennaSources:
all: "みんなのノート"
homeTimeline: "フォローしとるユーザーのノート"
@@ -1587,6 +1625,7 @@ _notification:
pollEnded: "アンケートの結果が出たみたいや"
unreadAntennaNote: "アンテナ {name}"
emptyPushNotificationMessage: "プッシュ通知の更新をしといたで"
+ achievementEarned: "実績を獲得しとるで"
_types:
all: "すべて"
follow: "フォロー"
diff --git a/locales/lo-LA.yml b/locales/lo-LA.yml
index befb2eb369..cfda4e0e9e 100644
--- a/locales/lo-LA.yml
+++ b/locales/lo-LA.yml
@@ -99,18 +99,84 @@ followRequestPending: "ປະຕິບັດຕາມຄໍາຮ້ອງຂໍ
enterEmoji: "ປ້ອນອີໂມຈິ"
renote: "Renote"
unrenote: "ເລີກ Renote"
+renoted: "ເກັບບັນທຶກໄວ້"
+quote: "ລວມຂໍ້ຄວາມອ້າງອີງ"
+pinnedNote: "ບັນທຶກທີ່ປັກໝຸດໄວ້"
pinned: "ປັກໝຸດໄປຫາໂປຣໄຟລ໌"
+you: "ເຈົ້າ"
+clickToShow: "ກົດເພື່ອສະແດງໃຫ້ເຫັນ"
+sensitive: "NSFW"
+add: "ເພີ່ມ"
+reaction: "ປະຕິກິລິຍາ"
+reactions: "ປະຕິກິລິຍາ"
+mute: "ປີດສຽງ"
+unmute: "ເປີດສຽງ"
+block: "ບ໋ອກ"
+unblock: "ຍົກເລີກກາຮົບລັອກ"
+suspend: "ລະງັບ"
+unsuspend: "ເຊົາ​ລະ​ງັບ"
+selectList: "ເລືອກບັນຊີລາຍການ"
+selectWidget: "ເລືອກວິກເຈັດ"
+editWidgets: "ແກ້ໄຂ Widget"
+editWidgetsExit: "ສຳເລັດແລ້ວ"
+customEmojis: "ອີໂມຈິແບບກຳນົດເອງ"
+emoji: "ອີໂມຈິ"
+emojis: "ອີໂມຈິ"
+emojiName: "ຊື່ Emoji"
+emojiUrl: "URL ອີໂມຈິ"
+addEmoji: "ຕື່ມອີໂມຈິ"
+flagAsBot: "ໝາຍບັນຊີນີ້ເປັນບັອດ"
+flagAsCat: "ໝາຍບັນຊີນີ້ເປັນແມວ"
+flagAsCatDescription: "ເປີດໃຊ້ຕົວເລືອກນີ້ເພື່ອໝາຍບັນຊີນີ້ເປັນແມວ"
+flagShowTimelineReplies: "ສະແດງການຕອບກັບໃນທາມລາຍ"
+flagShowTimelineRepliesDescription: "ສະແດງການຕອບກັບຂອງຜູ້ໃຊ້ຕໍ່ກັບບັນທຶກຂອງຜູ້ໃຊ້ອື່ນໃນທາມລາຍຖ້າເປີດໃຊ້ງານ"
+autoAcceptFollowed: "ອະນຸມັດອັດຕະໂນມັດຕາມຄຳຮ້ອງຂໍຈາກຜູ້ໃຊ້ທີ່ທ່ານກຳລັງຕິດຕາມຢູ່"
addAccount: "ເພີ່ມບັນຊີ"
loginFailed: "ການເຂົ້າສູ່ລະບົບບໍ່ສຳເລັດ"
general: "ທົ່ວໄປ"
wallpaper: "ພາບພື້ນຫລັງ"
setWallpaper: "ຕັ້ງເປັນພາບພື້ນຫຼັງ"
instances: "ອີນສະແຕນ"
+instanceInfo: "ອີນສະແຕນ"
statistics: "ສະຖິຕິ"
clearQueue: "ລ້າງຄິວ"
clearCachedFiles: "ລຶບລ້າງແຄສ"
editProfile: "ແກ້ໄຂໂປຣໄຟລ໌"
+done: "ສຳເລັດ"
+processing: "ກຳລັງປະມວນຜົນ"
+preview: "ສະແດງເປັນຕົວຢ່າງ"
+default: "ຄ່າເລີ່ມຕົ້ນ"
+blocked: "ບລັອກແລ້ວ "
+all: "ທັງໝົດ"
+subscribing: "ສະໝັກສະມາຊິກແລັວ"
+publishing: "ການ​ພິມ​ເຜີຍ​ແຜ່"
+notResponding: "ບໍ່ຕອບສະໜອງ"
+instanceFollowing: "ກຳລັງຕິດຕາມສຸດຕົວຢ່າງ"
+instanceFollowers: "ຜູ້ຕິດຕາມຕົວຢ່າງ"
+instanceUsers: "ຜູ້​ຊົມ​ໃຊ້​ຂອງ​ຕົວ​ຢ່າງ​ນີ້​"
+changePassword: "ປ່ຽນ​ລະ​ຫັດ​ຜ່ານ"
+featured: "ໄຮໄລທ໌"
+announcements: "ປະກາດ"
remove: "ລຶບ"
+messaging: "ແຊ໋ດ"
+tos: "ເງື່ອນໄຂການໃຫ້ບໍລິການ"
+start: "ເລີ່ມຕົ້ນນຳໃຊ້ເລີຍ"
+home: "ໜ້າຫຼັກ"
+images: "ຮູບພາບ"
+birthday: "ວັນເກີດ"
+registeredDate: "ວັນທີ່ເປັນສະມາຊິກ"
+location: "ທີ່ຕັ້ງ"
+theme: "ແທ໋ມ"
+light: "ສະຫວ່າງ"
+dark: "ມືດ"
+lightThemes: "ຊຸດຮູບແບບສະຫວ່າງ"
+darkThemes: "ຮູບແບບສີສັນມືດ"
+fileName: "ຊື່ໄຟລ໌"
+selectFile: "ເລືອກໄຟລ໌"
+selectFiles: "ເລືອກໄຟລ໌"
+nsfw: "NSFW"
+accept: "ອະນຸຍາດ"
+pinnedNotes: "ບັນທຶກທີ່ປັກໝຸດໄວ້"
userList: "ລາຍການ"
smtpUser: "ຊື່ຜູ້ໃຊ້"
smtpPass: "ລະຫັດຜ່ານ"
@@ -123,6 +189,8 @@ _email:
title: "ໄດ້ຕິດຕາມທ່ານ"
_mfm:
mention: "ໄດ້ກ່າວມາ"
+ quote: "ລວມຂໍ້ຄວາມອ້າງອີງ"
+ emoji: "ອີໂມຈິແບບກຳນົດເອງ"
search: "ຄົ້ນຫາ"
_theme:
keys:
@@ -131,25 +199,39 @@ _theme:
_sfx:
note: "ບັນທຶກ"
notification: "ການແຈ້ງເຕືອນ"
+ chat: "ແຊ໋ດ"
_widgets:
profile: "ໂພຼຟາຍ"
+ instanceInfo: "ອີນສະແຕນ"
notifications: "ການແຈ້ງເຕືອນ"
timeline: "​ເສັ້ນກຳ​ນົດ​ເວ​ລາ​"
+ _userList:
+ chooseList: "ເລືອກບັນຊີລາຍການ"
_cw:
show: "ໂຫຼດເພີ່ມເຕີມ"
_visibility:
+ home: "ໜ້າຫຼັກ"
followers: "ຜູ້ຕິດຕາມ"
_profile:
username: "ຊື່ຜູ້ໃຊ້"
_exportOrImport:
followingList: "ກຳລັງຕິດຕາມ"
+ muteList: "ປີດສຽງ"
+ blockingList: "ບ໋ອກ"
userLists: "ລາຍການ"
+_timelines:
+ home: "ໜ້າຫຼັກ"
+_pages:
+ blocks:
+ image: "ຮູບພາບ"
_notification:
youWereFollowed: "ໄດ້ຕິດຕາມທ່ານ"
_types:
follow: "ກຳລັງຕິດຕາມ"
mention: "ໄດ້ກ່າວມາ"
renote: "Renote"
+ quote: "ລວມຂໍ້ຄວາມອ້າງອີງ"
+ reaction: "ປະຕິກິລິຍາ"
_actions:
reply: "ຕອບ​ໄປ​ທີ"
renote: "Renote"
diff --git a/locales/th-TH.yml b/locales/th-TH.yml
index 0f5ff62485..010e32426c 100644
--- a/locales/th-TH.yml
+++ b/locales/th-TH.yml
@@ -940,6 +940,8 @@ cannotPerformTemporaryDescription: "การดําเนินการน
preset: "พรีเซ็ต"
selectFromPresets: "เลือกจากการพรีเซ็ต"
achievements: "ความสำเร็จ"
+gotInvalidResponseError: "การตอบสนองเซิร์ฟเวอร์ไม่ถูกต้อง"
+gotInvalidResponseErrorDescription: "เซิร์ฟเวอร์อาจไม่สามารถเข้าถึงได้หรืออาจจะกำลังอยู่ในระหว่างปรับปรุง กรุณาลองใหม่อีกครั้งในภายหลังนะคะ"
_achievements:
earnedAt: "ได้รับเมื่อ"
_types:
@@ -1594,12 +1596,15 @@ _permissions:
"read:gallery-likes": "ดูรายการโพสต์ในแกลเลอรีที่ชอบของคุณ"
"write:gallery-likes": "แก้ไขรายการโพสต์ในแกลเลอรีที่ชอบของคุณ"
_auth:
+ shareAccessTitle: "การให้สิทธิ์แอปพลิเคชัน"
shareAccess: "คุณต้องการอนุญาตให้ \"{name}\" เข้าถึงบัญชีนี้เลยมั้ย?"
shareAccessAsk: "คุณแน่ใจแล้วจริงๆหรอว่าต้องการอนุญาตให้แอปพลิเคชันนี้เข้าถึงบัญชีของคุณแน่ใจแล้วหรอ?"
+ permission: "{name} ได้ขอสิทธิ์การเข้าถึงดังต่อไปนี้"
permissionAsk: "แอปพลิเคชันนี้ขอสิทธิ์ดังต่อไปนี้"
pleaseGoBack: "กรุณากลับไปที่แอปพลิเคชัน"
callback: "กำลังกลับไปที่แอปพลิเคชัน"
denied: "ปฏิเสธการเข้าใช้"
+ pleaseLogin: "กรุณาเข้าสู่ระบบเพื่ออนุมัติแอปพลิเคชัน"
_antennaSources:
all: "โน้ตทั้งหมด"
homeTimeline: "โน้ตจากผู้ใช้ที่ติดตาม"
diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml
index 9a63bdec4e..a108158882 100644
--- a/locales/zh-CN.yml
+++ b/locales/zh-CN.yml
@@ -129,6 +129,7 @@ unblockConfirm: "确定要解除拉黑吗?"
suspendConfirm: "要冻结吗?"
unsuspendConfirm: "要解除冻结吗?"
selectList: "选择列表"
+selectChannel: "选择频道"
selectAntenna: "选择天线"
selectWidget: "选择小工具"
editWidgets: "编辑部件"
@@ -256,6 +257,8 @@ noMoreHistory: "没有更多的历史记录"
startMessaging: "添加聊天"
nUsersRead: "{n}人已读"
agreeTo: "勾选则表示已阅读并同意{0}"
+agreeBelow: "同意以下观点"
+basicNotesBeforeCreateAccount: "基本注意事项"
tos: "服务条款"
start: "开始"
home: "首页"
@@ -861,6 +864,8 @@ failedToFetchAccountInformation: "获取账户信息失败"
rateLimitExceeded: "已超過速率限制"
cropImage: "剪裁图像"
cropImageAsk: "是否要裁剪图像?"
+cropYes: "已裁剪"
+cropNo: "就这样吧!"
file: "文件"
recentNHours: "最近{n}小时"
recentNDays: "最近{n}天"
@@ -939,6 +944,8 @@ cannotPerformTemporaryDescription: "因操作过于频繁,暂时不可用,
preset: "預設值"
selectFromPresets: "從預設值中選擇"
achievements: "成就"
+gotInvalidResponseError: "服务器无应答"
+gotInvalidResponseErrorDescription: "您的网络连接可能出现了问题, 或是远程服务器暂时不可用. 请稍后重试。"
_achievements:
earnedAt: "达成时间"
_types:
@@ -1122,7 +1129,7 @@ _achievements:
description: "在0点发布一篇帖子"
flavor: "嘣 嘣 嘣 Biu——!"
_selfQuote:
- title: "自我提及"
+ title: "自我引用"
description: "引用了自己的帖子"
_htl20npm:
title: "流动的时间线"
@@ -1593,12 +1600,15 @@ _permissions:
"read:gallery-likes": "读取喜欢的图片"
"write:gallery-likes": "操作喜欢的图片"
_auth:
+ shareAccessTitle: "应用程序授权许可"
shareAccess: "您要授权允许“{name}”访问您的帐户吗?"
shareAccessAsk: "您确定要授权此应用程序访问您的帐户吗?"
+ permission: "{name}需要以下权限"
permissionAsk: "这个应用程序需要以下权限"
pleaseGoBack: "请返回到应用程序"
callback: "回到应用程序"
denied: "拒绝访问"
+ pleaseLogin: "在对应用进行授权许可之前,请先登录"
_antennaSources:
all: "所有帖子"
homeTimeline: "已关注用户的帖子"
diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml
index 570afce8fa..2e1787e7ae 100644
--- a/locales/zh-TW.yml
+++ b/locales/zh-TW.yml
@@ -129,6 +129,7 @@ unblockConfirm: "確定解除封鎖此用戶?"
suspendConfirm: "確定凍結此帳號?"
unsuspendConfirm: "確定解凍此帳號?"
selectList: "選擇清單"
+selectChannel: "選擇頻道"
selectAntenna: "選擇天線"
selectWidget: "選擇小工具"
editWidgets: "編輯小工具"
@@ -256,6 +257,8 @@ noMoreHistory: "沒有更多歷史紀錄"
startMessaging: "開始聊天"
nUsersRead: "{n}人已讀"
agreeTo: "我同意{0}"
+agreeBelow: "同意以下內容"
+basicNotesBeforeCreateAccount: "基本注意事項"
tos: "使用條款"
start: "開始"
home: "首頁"
@@ -861,6 +864,8 @@ failedToFetchAccountInformation: "取得帳戶資訊失敗"
rateLimitExceeded: "已超過速率限制"
cropImage: "圖片裁剪"
cropImageAsk: "要剪裁圖片嗎?"
+cropYes: "裁剪"
+cropNo: "使用原圖"
file: "檔案"
recentNHours: "過去{n}小時"
recentNDays: "過去{n}天"
@@ -1595,12 +1600,15 @@ _permissions:
"read:gallery-likes": "讀取喜歡的圖片"
"write:gallery-likes": "操作喜歡的圖片"
_auth:
+ shareAccessTitle: "應用程式的存取權限"
shareAccess: "要授權「“{name}”」存取您的帳戶嗎?"
shareAccessAsk: "您確定要授權這個應用程式使用您的帳戶嗎?"
+ permission: "{name}要求以下的權限"
permissionAsk: "此應用程式需要以下權限"
pleaseGoBack: "請返回至應用程式"
callback: "回到應用程式"
denied: "拒絕訪問"
+ pleaseLogin: "必須登入以提供應用程式的存取權限。"
_antennaSources:
all: "全部貼文"
homeTimeline: "來自已追隨使用者的貼文"
diff --git a/package.json b/package.json
index 578bcb76a4..97c9dea7d2 100644
--- a/package.json
+++ b/package.json
@@ -1,12 +1,12 @@
{
"name": "misskey",
- "version": "13.5.5",
+ "version": "13.5.6",
"codename": "nasubi",
"repository": {
"type": "git",
"url": "https://github.com/misskey-dev/misskey.git"
},
- "packageManager": "pnpm@7.24.3",
+ "packageManager": "pnpm@7.27.0",
"workspaces": [
"packages/frontend",
"packages/backend",
diff --git a/packages/backend/src/server/FileServerService.ts b/packages/backend/src/server/FileServerService.ts
index 4bd6d0f556..49ded6c28e 100644
--- a/packages/backend/src/server/FileServerService.ts
+++ b/packages/backend/src/server/FileServerService.ts
@@ -255,8 +255,21 @@ export class FileServerService {
const isConvertibleImage = isMimeImage(file.mime, 'sharp-convertible-image');
const isAnimationConvertibleImage = isMimeImage(file.mime, 'sharp-animation-convertible-image');
+ if (
+ 'emoji' in request.query ||
+ 'avatar' in request.query ||
+ 'static' in request.query ||
+ 'preview' in request.query ||
+ 'badge' in request.query
+ ) {
+ if (!isConvertibleImage) {
+ // 画像でないなら404でお茶を濁す
+ throw new StatusError('Unexpected mime', 404);
+ }
+ }
+
let image: IImageStreamable | null = null;
- if (('emoji' in request.query || 'avatar' in request.query) && isConvertibleImage) {
+ if ('emoji' in request.query || 'avatar' in request.query) {
if (!isAnimationConvertibleImage && !('static' in request.query)) {
image = {
data: fs.createReadStream(file.path),
@@ -277,16 +290,11 @@ export class FileServerService {
type: 'image/webp',
};
}
- } else if ('static' in request.query && isConvertibleImage) {
+ } else if ('static' in request.query) {
image = this.imageProcessingService.convertToWebpStream(file.path, 498, 280);
- } else if ('preview' in request.query && isConvertibleImage) {
+ } else if ('preview' in request.query) {
image = this.imageProcessingService.convertToWebpStream(file.path, 200, 200);
} else if ('badge' in request.query) {
- if (!isConvertibleImage) {
- // 画像でないなら404でお茶を濁す
- throw new StatusError('Unexpected mime', 404);
- }
-
const mask = sharp(file.path)
.resize(96, 96, {
fit: 'inside',
diff --git a/packages/frontend/src/components/MkAchievements.vue b/packages/frontend/src/components/MkAchievements.vue
index 19d04721d8..d30037dcf9 100644
--- a/packages/frontend/src/components/MkAchievements.vue
+++ b/packages/frontend/src/components/MkAchievements.vue
@@ -107,6 +107,7 @@ onMounted(() => {
}
.iconFrame {
+ position: relative;
width: 58px;
height: 58px;
padding: 6px;
diff --git a/packages/frontend/src/components/MkCwButton.vue b/packages/frontend/src/components/MkCwButton.vue
index 651b20cefe..e0885f5550 100644
--- a/packages/frontend/src/components/MkCwButton.vue
+++ b/packages/frontend/src/components/MkCwButton.vue
@@ -1,5 +1,5 @@
<template>
-<button class="_button" :class="$style.root" @click="toggle">
+<button class="_button" :class="$style.root" @mousedown="toggle">
<b>{{ modelValue ? i18n.ts._cw.hide : i18n.ts._cw.show }}</b>
<span v-if="!modelValue" :class="$style.label">{{ label }}</span>
</button>
diff --git a/packages/frontend/src/components/MkDialog.vue b/packages/frontend/src/components/MkDialog.vue
index 74cb534859..da4db63406 100644
--- a/packages/frontend/src/components/MkDialog.vue
+++ b/packages/frontend/src/components/MkDialog.vue
@@ -28,8 +28,8 @@
</template>
</MkSelect>
<div v-if="(showOkButton || showCancelButton) && !actions" :class="$style.buttons">
- <MkButton v-if="showOkButton" inline primary :autofocus="!input && !select" @click="ok">{{ (showCancelButton || input || select) ? i18n.ts.ok : i18n.ts.gotIt }}</MkButton>
- <MkButton v-if="showCancelButton || input || select" inline @click="cancel">{{ i18n.ts.cancel }}</MkButton>
+ <MkButton v-if="showOkButton" inline primary :autofocus="!input && !select" @click="ok">{{ okText ?? ((showCancelButton || input || select) ? i18n.ts.ok : i18n.ts.gotIt) }}</MkButton>
+ <MkButton v-if="showCancelButton || input || select" inline @click="cancel">{{ cancelText ?? i18n.ts.cancel }}</MkButton>
</div>
<div v-if="actions" :class="$style.buttons">
<MkButton v-for="action in actions" :key="action.text" inline :primary="action.primary" @click="() => { action.callback(); close(); }">{{ action.text }}</MkButton>
@@ -82,6 +82,8 @@ const props = withDefaults(defineProps<{
showOkButton?: boolean;
showCancelButton?: boolean;
cancelableByBgClick?: boolean;
+ okText?: string;
+ cancelText?: string;
}>(), {
type: 'info',
showOkButton: true,
diff --git a/packages/frontend/src/components/MkMediaBanner.vue b/packages/frontend/src/components/MkMediaBanner.vue
index c4af1ee8d0..c0401a6455 100644
--- a/packages/frontend/src/components/MkMediaBanner.vue
+++ b/packages/frontend/src/components/MkMediaBanner.vue
@@ -56,7 +56,7 @@ onMounted(() => {
width: 100%;
border-radius: 4px;
margin-top: 4px;
- overflow: clip;
+ // overflow: clip;
--plyr-color-main: var(--accent);
--plyr-audio-controls-background: var(--bg);
@@ -99,7 +99,7 @@ onMounted(() => {
> .audio {
border-radius: 8px;
- overflow: clip;
+ // overflow: clip;
}
}
</style>
diff --git a/packages/frontend/src/components/MkSignup.vue b/packages/frontend/src/components/MkSignup.vue
index c60c566f86..d8703a0b1b 100644
--- a/packages/frontend/src/components/MkSignup.vue
+++ b/packages/frontend/src/components/MkSignup.vue
@@ -50,13 +50,13 @@
<span v-if="passwordRetypeState == 'not-match'" style="color: var(--error)"><i class="ti ti-alert-triangle ti-fw"></i> {{ i18n.ts.passwordNotMatched }}</span>
</template>
</MkInput>
- <MkSwitch v-if="instance.tosUrl" v-model="ToSAgreement" class="tou">
- <I18n :src="i18n.ts.agreeTo">
- <template #0>
- <a :href="instance.tosUrl" class="_link" target="_blank">{{ i18n.ts.tos }}</a>
- </template>
- </I18n>
+ <MkSwitch v-model="ToSAgreement" class="tou">
+ <template #label>{{ i18n.ts.agreeBelow }}</template>
</MkSwitch>
+ <ul style="margin: 0; padding-left: 2em;">
+ <li v-if="instance.tosUrl"><a :href="instance.tosUrl" class="_link" target="_blank">{{ i18n.ts.tos }}</a></li>
+ <li><a href="https://misskey-hub.net/docs/notes.html" class="_link" target="_blank">{{ i18n.ts.basicNotesBeforeCreateAccount }}</a></li>
+ </ul>
<MkCaptcha v-if="instance.enableHcaptcha" ref="hcaptcha" v-model="hCaptchaResponse" class="captcha" provider="hcaptcha" :sitekey="instance.hcaptchaSiteKey"/>
<MkCaptcha v-if="instance.enableRecaptcha" ref="recaptcha" v-model="reCaptchaResponse" class="captcha" provider="recaptcha" :sitekey="instance.recaptchaSiteKey"/>
<MkCaptcha v-if="instance.enableTurnstile" ref="turnstile" v-model="turnstileResponse" class="captcha" provider="turnstile" :sitekey="instance.turnstileSiteKey"/>
diff --git a/packages/frontend/src/components/global/MkAvatar.vue b/packages/frontend/src/components/global/MkAvatar.vue
index 812f30439b..9ad06545f2 100644
--- a/packages/frontend/src/components/global/MkAvatar.vue
+++ b/packages/frontend/src/components/global/MkAvatar.vue
@@ -1,11 +1,19 @@
<template>
-<span v-if="!link" v-user-preview="preview ? user.id : undefined" :class="[$style.root, { [$style.cat]: user.isCat, [$style.square]: $store.state.squareAvatars }]" class="_noSelect" :style="{ color }" :title="acct(user)" @click="onClick">
+<span v-if="!link" v-user-preview="preview ? user.id : undefined" class="_noSelect" :class="[$style.root, { [$style.cat]: user.isCat, [$style.square]: $store.state.squareAvatars }]" :style="{ color }" :title="acct(user)" @click="onClick">
<img :class="$style.inner" :src="url" decoding="async"/>
<MkUserOnlineIndicator v-if="indicator" :class="$style.indicator" :user="user"/>
+ <template v-if="user.isCat">
+ <div :class="$style.earLeft"/>
+ <div :class="$style.earRight"/>
+ </template>
</span>
-<MkA v-else v-user-preview="preview ? user.id : undefined" class="_noSelect" :class="[$style.root, { [$style.cat]: user.isCat, [$style.square]: $store.state.squareAvatars }]" :style="{ color }" :to="userPage(user)" :title="acct(user)" :target="target">
+<MkA v-else v-user-preview="preview ? user.id : undefined" class="_noSelect" :class="[$style.root, { [$style.cat]: user.isCat, [$style.square]: $store.state.squareAvatars }]" :style="{ color }" :title="acct(user)" :to="userPage(user)" :target="target">
<img :class="$style.inner" :src="url" decoding="async"/>
<MkUserOnlineIndicator v-if="indicator" :class="$style.indicator" :user="user"/>
+ <template v-if="user.isCat">
+ <div :class="$style.earLeft"/>
+ <div :class="$style.earRight"/>
+ </template>
</MkA>
</template>
@@ -110,32 +118,41 @@ watch(() => props.user.avatarBlurhash, () => {
}
.cat {
- &:before, &:after {
- background: #df548f;
- border: solid 4px currentColor;
- box-sizing: border-box;
- content: '';
+ > .earLeft,
+ > .earRight {
+ contain: strict;
display: inline-block;
height: 50%;
width: 50%;
+ background: currentColor;
+
+ &::before {
+ contain: strict;
+ content: '';
+ display: block;
+ width: 60%;
+ height: 60%;
+ margin: 20%;
+ background: #df548f;
+ }
}
- &:before {
+ > .earLeft {
border-radius: 0 75% 75%;
transform: rotate(37.5deg) skew(30deg);
}
- &:after {
+ > .earRight {
border-radius: 75% 0 75% 75%;
transform: rotate(-37.5deg) skew(-30deg);
}
&:hover {
- &:before {
+ > .earLeft {
animation: earwiggleleft 1s infinite;
}
- &:after {
+ > .earRight {
animation: earwiggleright 1s infinite;
}
}
diff --git a/packages/frontend/src/os.ts b/packages/frontend/src/os.ts
index 52469b6d04..e21a21ef76 100644
--- a/packages/frontend/src/os.ts
+++ b/packages/frontend/src/os.ts
@@ -171,6 +171,8 @@ export function confirm(props: {
type: 'error' | 'info' | 'success' | 'warning' | 'waiting' | 'question';
title?: string | null;
text?: string | null;
+ okText?: string;
+ cancelText?: string;
}): Promise<{ canceled: boolean }> {
return new Promise((resolve, reject) => {
popup(MkDialog, {
diff --git a/packages/frontend/src/pages/auth.form.vue b/packages/frontend/src/pages/auth.form.vue
index 801295fce9..f8484185f5 100644
--- a/packages/frontend/src/pages/auth.form.vue
+++ b/packages/frontend/src/pages/auth.form.vue
@@ -1,60 +1,66 @@
<template>
-<section class="">
- <div class="">{{ $t('_auth.shareAccess', { name: app.name }) }}</div>
- <div class="">
- <h2>{{ app.name }}</h2>
- <p class="id">{{ app.id }}</p>
- <p class="description">{{ app.description }}</p>
- </div>
- <div class="">
- <h2>{{ $ts._auth.permissionAsk }}</h2>
- <ul>
- <li v-for="p in app.permission" :key="p">{{ $t(`_permissions.${p}`) }}</li>
- </ul>
- </div>
- <div class="">
- <MkButton inline @click="cancel">{{ $ts.cancel }}</MkButton>
- <MkButton inline primary @click="accept">{{ $ts.accept }}</MkButton>
- </div>
-</section>
+ <section>
+ <div v-if="app.permission.length > 0">
+ <p>{{ $t('_auth.permission', { name }) }}</p>
+ <ul>
+ <li v-for="p in app.permission" :key="p">{{ $t(`_permissions.${p}`) }}</li>
+ </ul>
+ </div>
+ <div>{{ i18n.t('_auth.shareAccess', { name: `${name} (${app.id})` }) }}</div>
+ <div :class="$style.buttons">
+ <MkButton inline @click="cancel">{{ i18n.ts.cancel }}</MkButton>
+ <MkButton inline primary @click="accept">{{ i18n.ts.accept }}</MkButton>
+ </div>
+ </section>
</template>
-<script lang="ts">
-import { defineComponent } from 'vue';
+<script lang="ts" setup>
+import { } from 'vue';
import MkButton from '@/components/MkButton.vue';
import * as os from '@/os';
+import { i18n } from '@/i18n';
+import { AuthSession } from 'misskey-js/built/entities';
-export default defineComponent({
- components: {
- MkButton,
- },
- props: ['session'],
- computed: {
- name(): string {
- const el = document.createElement('div');
- el.textContent = this.app.name;
- return el.innerHTML;
- },
- app(): any {
- return this.session.app;
- },
- },
- methods: {
- cancel() {
- os.api('auth/deny', {
- token: this.session.token,
- }).then(() => {
- this.$emit('denied');
- });
- },
+const props = defineProps<{
+ session: AuthSession;
+}>();
- accept() {
- os.api('auth/accept', {
- token: this.session.token,
- }).then(() => {
- this.$emit('accepted');
- });
- },
- },
+const emit = defineEmits<{
+ (event: 'accepted'): void;
+ (event: 'denied'): void;
+}>();
+
+const app = $computed(() => props.session.app);
+
+const name = $computed(() => {
+ const el = document.createElement('div');
+ el.textContent = app.name;
+ return el.innerHTML;
});
+
+function cancel() {
+ os.api('auth/deny', {
+ token: props.session.token,
+ }).then(() => {
+ emit('denied');
+ });
+}
+
+function accept() {
+ os.api('auth/accept', {
+ token: props.session.token,
+ }).then(() => {
+ emit('accepted');
+ });
+}
+
</script>
+
+<style lang="scss" module>
+.buttons {
+ margin-top: 16px;
+ display: flex;
+ gap: 8px;
+ flex-wrap: wrap;
+}
+</style>
diff --git a/packages/frontend/src/pages/auth.vue b/packages/frontend/src/pages/auth.vue
index b7727ca30d..50afffc460 100644
--- a/packages/frontend/src/pages/auth.vue
+++ b/packages/frontend/src/pages/auth.vue
@@ -1,93 +1,105 @@
<template>
-<div v-if="$i && fetching" class="">
- <MkLoading/>
-</div>
-<div v-else-if="$i">
- <XForm
- v-if="state == 'waiting'"
- ref="form"
- class="form"
- :session="session"
- @denied="state = 'denied'"
- @accepted="accepted"
- />
- <div v-if="state == 'denied'" class="denied">
- <h1>{{ $ts._auth.denied }}</h1>
- </div>
- <div v-if="state == 'accepted'" class="accepted">
- <h1>{{ session.app.isAuthorized ? $t('already-authorized') : $ts.allowed }}</h1>
- <p v-if="session.app.callbackUrl">{{ $ts._auth.callback }}<MkEllipsis/></p>
- <p v-if="!session.app.callbackUrl">{{ $ts._auth.pleaseGoBack }}</p>
- </div>
- <div v-if="state == 'fetch-session-error'" class="error">
- <p>{{ $ts.somethingHappened }}</p>
- </div>
-</div>
-<div v-else class="signin">
- <MkSignin @login="onLogin"/>
-</div>
+<MkStickyContainer>
+ <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs" /></template>
+ <MkSpacer :content-max="500">
+ <div v-if="state == 'fetch-session-error'">
+ <p>{{ i18n.ts.somethingHappened }}</p>
+ </div>
+ <div v-else-if="$i && !session">
+ <MkLoading />
+ </div>
+ <div v-else-if="$i && session">
+ <XForm
+ v-if="state == 'waiting'"
+ class="form"
+ :session="session"
+ @denied="state = 'denied'"
+ @accepted="accepted"
+ />
+ <div v-if="state == 'denied'">
+ <h1>{{ i18n.ts._auth.denied }}</h1>
+ </div>
+ <div v-if="state == 'accepted' && session">
+ <h1>{{ session.app.isAuthorized ? $t('already-authorized') : i18n.ts.allowed }}</h1>
+ <p v-if="session.app.callbackUrl">{{ i18n.ts._auth.callback }}
+ <MkEllipsis />
+ </p>
+ <p v-if="!session.app.callbackUrl">{{ i18n.ts._auth.pleaseGoBack }}</p>
+ </div>
+ </div>
+ <div v-else>
+ <p :class="$style.loginMessage">{{ i18n.ts._auth.pleaseLogin }}</p>
+ <MkSignin @login="onLogin" />
+ </div>
+ </MkSpacer>
+</MkStickyContainer>
</template>
-<script lang="ts">
-import { defineComponent } from 'vue';
+<script lang="ts" setup>
+import { onMounted } from 'vue';
import XForm from './auth.form.vue';
import MkSignin from '@/components/MkSignin.vue';
import * as os from '@/os';
-import { login } from '@/account';
+import { $i, login } from '@/account';
+import { definePageMetadata } from '@/scripts/page-metadata';
+import { AuthSession } from 'misskey-js/built/entities';
+import { i18n } from '@/i18n';
-export default defineComponent({
- components: {
- XForm,
- MkSignin,
- },
- props: ['token'],
- data() {
- return {
- state: null,
- session: null,
- fetching: true,
- };
- },
- mounted() {
- if (!this.$i) return;
+const props = defineProps<{
+ token: string;
+}>();
- // Fetch session
- os.api('auth/session/show', {
- token: this.token,
- }).then(session => {
- this.session = session;
- this.fetching = false;
+let state = $ref<'waiting' | 'accepted' | 'fetch-session-error' | 'denied' | null>(null);
+let session = $ref<AuthSession | null>(null);
- // 既に連携していた場合
- if (this.session.app.isAuthorized) {
- os.api('auth/accept', {
- token: this.session.token,
- }).then(() => {
- this.accepted();
- });
- } else {
- this.state = 'waiting';
- }
- }).catch(error => {
- this.state = 'fetch-session-error';
- this.fetching = false;
+function accepted() {
+ state = 'accepted';
+ if (session && session.app.callbackUrl) {
+ const url = new URL(session.app.callbackUrl);
+ if (['javascript:', 'file:', 'data:', 'mailto:', 'tel:'].includes(url.protocol)) throw new Error('invalid url');
+ location.href = `${session.app.callbackUrl}?token=${session.token}`;
+ }
+}
+
+function onLogin(res) {
+ login(res.i);
+}
+
+onMounted(async () => {
+ if (!$i) return;
+
+ try {
+ session = await os.api('auth/session/show', {
+ token: props.token,
});
- },
- methods: {
- accepted() {
- this.state = 'accepted';
- if (this.session.app.callbackUrl) {
- const url = new URL(this.session.app.callbackUrl);
- if (['javascript:', 'file:', 'data:', 'mailto:', 'tel:'].includes(url.protocol)) throw new Error('invalid url');
- location.href = `${this.session.app.callbackUrl}?token=${this.session.token}`;
- }
- }, onLogin(res) {
- login(res.i);
- },
- },
+
+ // 既に連携していた場合
+ if (session.app.isAuthorized) {
+ await os.api('auth/accept', {
+ token: session.token,
+ });
+ accepted();
+ } else {
+ state = 'waiting';
+ }
+ } catch (e) {
+ state = 'fetch-session-error';
+ }
});
-</script>
-<style lang="scss" scoped>
+const headerActions = $computed(() => []);
+
+const headerTabs = $computed(() => []);
+
+definePageMetadata({
+ title: i18n.ts._auth.shareAccessTitle,
+ icon: 'ti ti-apps',
+});
+</script>
+<style lang="scss" module>
+.loginMessage {
+ text-align: center;
+ margin: 8px 0 24px;
+}
</style>
diff --git a/packages/frontend/src/pages/miauth.vue b/packages/frontend/src/pages/miauth.vue
index 9a4019e5b1..915adff277 100644
--- a/packages/frontend/src/pages/miauth.vue
+++ b/packages/frontend/src/pages/miauth.vue
@@ -1,41 +1,40 @@
<template>
-<MkSpacer :content-max="800">
- <div v-if="$i">
- <div v-if="state == 'waiting'" class="waiting">
- <div class="">
+<MkStickyContainer>
+ <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs" /></template>
+ <MkSpacer :content-max="800">
+ <div v-if="$i">
+ <div v-if="state == 'waiting'">
<MkLoading/>
</div>
- </div>
- <div v-if="state == 'denied'" class="denied">
- <div class="">
+ <div v-if="state == 'denied'">
<p>{{ i18n.ts._auth.denied }}</p>
</div>
- </div>
- <div v-else-if="state == 'accepted'" class="accepted">
- <div class="">
+ <div v-else-if="state == 'accepted'" class="accepted">
<p v-if="callback">{{ i18n.ts._auth.callback }}<MkEllipsis/></p>
<p v-else>{{ i18n.ts._auth.pleaseGoBack }}</p>
</div>
- </div>
- <div v-else class="">
- <div v-if="name" class="">{{ $t('_auth.shareAccess', { name: name }) }}</div>
- <div v-else class="">{{ i18n.ts._auth.shareAccessAsk }}</div>
- <div class="">
- <p>{{ i18n.ts._auth.permissionAsk }}</p>
- <ul>
- <li v-for="p in _permissions" :key="p">{{ $t(`_permissions.${p}`) }}</li>
- </ul>
- </div>
- <div class="">
- <MkButton inline @click="deny">{{ i18n.ts.cancel }}</MkButton>
- <MkButton inline primary @click="accept">{{ i18n.ts.accept }}</MkButton>
+ <div v-else>
+ <div v-if="_permissions.length > 0">
+ <p v-if="name">{{ $t('_auth.permission', { name }) }}</p>
+ <p v-else>{{ i18n.ts._auth.permissionAsk }}</p>
+ <ul>
+ <li v-for="p in _permissions" :key="p">{{ $t(`_permissions.${p}`) }}</li>
+ </ul>
+ </div>
+ <div v-if="name">{{ $t('_auth.shareAccess', { name }) }}</div>
+ <div v-else>{{ i18n.ts._auth.shareAccessAsk }}</div>
+ <div :class="$style.buttons">
+ <MkButton inline @click="deny">{{ i18n.ts.cancel }}</MkButton>
+ <MkButton inline primary @click="accept">{{ i18n.ts.accept }}</MkButton>
+ </div>
</div>
</div>
- </div>
- <div v-else class="signin">
- <MkSignin @login="onLogin"/>
- </div>
-</MkSpacer>
+ <div v-else>
+ <p :class="$style.loginMessage">{{ i18n.ts._auth.pleaseLogin }}</p>
+ <MkSignin @login="onLogin"/>
+ </div>
+ </MkSpacer>
+</MkStickyContainer>
</template>
<script lang="ts" setup>
@@ -45,6 +44,7 @@ import MkButton from '@/components/MkButton.vue';
import * as os from '@/os';
import { $i, login } from '@/account';
import { i18n } from '@/i18n';
+import { definePageMetadata } from '@/scripts/page-metadata';
const props = defineProps<{
session: string;
@@ -54,7 +54,7 @@ const props = defineProps<{
permission: string; // コンマ区切り
}>();
-const _permissions = props.permission.split(',');
+const _permissions = props.permission ? props.permission.split(',') : [];
let state = $ref<string | null>(null);
@@ -83,8 +83,27 @@ function deny(): void {
function onLogin(res): void {
login(res.i);
}
+
+const headerActions = $computed(() => []);
+
+const headerTabs = $computed(() => []);
+
+definePageMetadata({
+ title: 'MiAuth',
+ icon: 'ti ti-apps',
+});
</script>
-<style lang="scss" scoped>
+<style lang="scss" module>
+.buttons {
+ margin-top: 16px;
+ display: flex;
+ gap: 8px;
+ flex-wrap: wrap;
+}
+.loginMessage {
+ text-align: center;
+ margin: 8px 0 24px;
+}
</style>
diff --git a/packages/frontend/src/pages/settings/profile.vue b/packages/frontend/src/pages/settings/profile.vue
index da7d3d3703..3647e90ce7 100644
--- a/packages/frontend/src/pages/settings/profile.vue
+++ b/packages/frontend/src/pages/settings/profile.vue
@@ -150,6 +150,8 @@ function changeAvatar(ev) {
const { canceled } = await os.confirm({
type: 'question',
text: i18n.t('cropImageAsk'),
+ okText: i18n.ts.cropYes,
+ cancelText: i18n.ts.cropNo,
});
if (!canceled) {
@@ -174,6 +176,8 @@ function changeBanner(ev) {
const { canceled } = await os.confirm({
type: 'question',
text: i18n.t('cropImageAsk'),
+ okText: i18n.ts.cropYes,
+ cancelText: i18n.ts.cropNo,
});
if (!canceled) {
diff --git a/packages/frontend/src/ui/_common_/navbar-for-mobile.vue b/packages/frontend/src/ui/_common_/navbar-for-mobile.vue
index 989d861d27..357db5599f 100644
--- a/packages/frontend/src/ui/_common_/navbar-for-mobile.vue
+++ b/packages/frontend/src/ui/_common_/navbar-for-mobile.vue
@@ -35,7 +35,7 @@
<i class="icon ti ti-pencil ti-fw"></i><span class="text">{{ i18n.ts.note }}</span>
</button>
<button v-click-anime class="item _button account" @click="openAccountMenu">
- <MkAvatar :user="$i" class="avatar"/><MkAcct class="text" :user="$i"/>
+ <MkAvatar :user="$i" class="avatar"/><MkAcct class="text _nowrap" :user="$i"/>
</button>
</div>
</div>
@@ -168,20 +168,25 @@ function more() {
display: flex;
align-items: center;
padding-left: 30px;
- text-overflow: ellipsis;
- overflow: hidden;
- white-space: nowrap;
width: 100%;
text-align: left;
box-sizing: border-box;
margin-top: 16px;
> .avatar {
+ display: block;
+ flex-shrink: 0;
position: relative;
width: 32px;
aspect-ratio: 1;
margin-right: 8px;
}
+
+ > .text {
+ display: block;
+ flex-shrink: 1;
+ padding-right: 8px;
+ }
}
}
diff --git a/packages/frontend/src/ui/_common_/navbar.vue b/packages/frontend/src/ui/_common_/navbar.vue
index e90098397a..3c161f6797 100644
--- a/packages/frontend/src/ui/_common_/navbar.vue
+++ b/packages/frontend/src/ui/_common_/navbar.vue
@@ -45,7 +45,7 @@
<i class="icon ti ti-pencil ti-fw"></i><span class="text">{{ i18n.ts.note }}</span>
</button>
<button v-click-anime v-tooltip.noDelay.right="`${i18n.ts.account}: @${$i.username}`" class="item _button account" @click="openAccountMenu">
- <MkAvatar :user="$i" class="avatar"/><MkAcct class="text" :user="$i"/>
+ <MkAvatar :user="$i" class="avatar"/><MkAcct class="text _nowrap" :user="$i"/>
</button>
</div>
</div>
@@ -217,20 +217,25 @@ function more(ev: MouseEvent) {
display: flex;
align-items: center;
padding-left: 30px;
- text-overflow: ellipsis;
- overflow: hidden;
- white-space: nowrap;
width: 100%;
text-align: left;
box-sizing: border-box;
margin-top: 16px;
> .avatar {
+ display: block;
+ flex-shrink: 0;
position: relative;
width: 32px;
aspect-ratio: 1;
margin-right: 8px;
}
+
+ > .text {
+ display: block;
+ flex-shrink: 1;
+ padding-right: 8px;
+ }
}
}