Merge branch 'develop'
This commit is contained in:
commit
000f876084
11
CHANGELOG.md
11
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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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: "全てのノート"
|
||||
|
|
|
@ -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: "フォロー"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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: "โน้ตจากผู้ใช้ที่ติดตาม"
|
||||
|
|
|
@ -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: "已关注用户的帖子"
|
||||
|
|
|
@ -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: "來自已追隨使用者的貼文"
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -107,6 +107,7 @@ onMounted(() => {
|
|||
}
|
||||
|
||||
.iconFrame {
|
||||
position: relative;
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
padding: 6px;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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, {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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';
|
||||
}
|
||||
});
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts._auth.shareAccessTitle,
|
||||
icon: 'ti ti-apps',
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
<style lang="scss" module>
|
||||
.loginMessage {
|
||||
text-align: center;
|
||||
margin: 8px 0 24px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue