Compare commits

...

18 Commits

Author SHA1 Message Date
syuilo
000f876084 Merge branch 'develop' 2023-02-10 20:14:47 +09:00
syuilo
2d11c558fa 13.5.6 2023-02-10 20:14:38 +09:00
syuilo
ac6b02af40 New Crowdin updates (#9852)
* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Thai)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (Lao)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Chinese Traditional)
2023-02-10 20:13:07 +09:00
Nya Candy
7d91912cfd fix: prevent clipping audio plyr's tooltip (#9850) 2023-02-10 18:29:54 +09:00
syuilo
3c504b4b08 chore(client): improve usability 2023-02-10 11:04:11 +09:00
syuilo
adad4bcfe3 クロップ時の質問を分かりやすく 2023-02-10 10:45:32 +09:00
syuilo
b3e8671dd9 利用規約同意UIの調整 2023-02-10 10:36:25 +09:00
syuilo
0f8c890761 🎨 2023-02-10 09:49:52 +09:00
tamaina
512e451f24 app auth / miauthの文言編集 2023-02-09 17:29:22 +00:00
tamaina
ca0d53ec5d enhance(client): /authおよびMiAuthのUIをブラッシュアップ
Fix #9742
2023-02-09 17:18:27 +00:00
Acid Chicken (硫酸鶏)
686a709e87 chore: determine dimensions of the helix of cat ears based on the size of avatars (#9836)
* chore: determine dimensions of the helix of cat ears based on the size of avatars

* Update MkAvatar.vue

* Update packages/frontend/src/components/global/MkAvatar.vue

---------

Co-authored-by: tamaina <tamaina@hotmail.co.jp>
2023-02-10 00:36:05 +09:00
tamaina
83fb629f0b 🎨 2023-02-09 15:34:49 +00:00
tamaina
35eeeb25e3 update pnpm to 7.27.0 2023-02-09 15:05:23 +00:00
tamaina
19035c676c /proxyでemoji, avatarなどの命令がありかつ画像でないなら404を返すように 2023-02-09 12:39:24 +00:00
syuilo
61ffe7417c Merge branch 'develop' 2023-02-09 20:48:07 +09:00
syuilo
7651353f39 13.5.5 2023-02-09 20:47:56 +09:00
syuilo
3f5b81060f New Crowdin updates (#9844)
* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Chinese Traditional)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Thai)

* New translations ja-JP.yml (Lao)
2023-02-09 20:47:33 +09:00
syuilo
63dc66769f fix(client): webkitでMkMediaListが崩れるのを修正 2023-02-09 20:12:36 +09:00
26 changed files with 575 additions and 209 deletions

View File

@@ -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

View File

@@ -129,6 +129,7 @@ unblockConfirm: "Möchtest du diese Blockierung wirklich aufheben?"
suspendConfirm: "Möchtest du diesen Benutzer wirklich sperren?"
unsuspendConfirm: "Möchtest du diesen Benutzer wirklich entsperren?"
selectList: "Liste auswählen"
selectChannel: "Kanal auswählen"
selectAntenna: "Antenne auswählen"
selectWidget: "Widget auswählen"
editWidgets: "Widgets bearbeiten"
@@ -256,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"
@@ -861,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"
@@ -939,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:
@@ -1593,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"
@@ -1869,6 +1879,6 @@ _deck:
tl: "Chronik"
antenna: "Antennen"
list: "Listen"
channel: "Kanäle"
channel: "Kanal"
mentions: "Erwähnungen"
direct: "Direktnachrichten"

View File

@@ -129,6 +129,7 @@ unblockConfirm: "Are you sure that you want to unblock this account?"
suspendConfirm: "Are you sure that you want to suspend this account?"
unsuspendConfirm: "Are you sure that you want to unsuspend this account?"
selectList: "Select a list"
selectChannel: "Select a channel"
selectAntenna: "Select an antenna"
selectWidget: "Select a widget"
editWidgets: "Edit widgets"
@@ -256,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"
@@ -861,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"
@@ -939,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:
@@ -1593,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"
@@ -1869,6 +1879,6 @@ _deck:
tl: "Timeline"
antenna: "Antennas"
list: "List"
channel: "Channels"
channel: "Channel"
mentions: "Mentions"
direct: "Direct notes"

View File

@@ -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"

View File

@@ -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: "全てのノート"

View File

@@ -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: "フォロー"

View File

@@ -49,24 +49,196 @@ deleteAndEdit: "ລົບ​ແລະ​ແກ້​ໄຂ​"
deleteAndEditConfirm: "ເຈົ້າ​ແນ່​ໃຈ​ບໍ່? ທີ່ທ່ານຕ້ອງການທີ່ຈະລຶບບັນທຶກນີ້ແລະແກ້ໄຂມັນ ທ່ານອາດຈະສູນເສຍການໂຕ້ຕອບ, ບັນທຶກ, ແລະການຕອບກັບທັງໝົດ"
addToList: "ເພີ່ມໃສ່ລາຍຊື່"
sendMessage: "ສົ່ງຂໍ້ຄວາມ"
copyRSS: "ສຳເນົາ RSS"
copyUsername: "ສຳເນົາຊື່ຜູ້ໃຊ້"
searchUser: "ຄົ້ນຫາຜູ້ໃຊ້"
reply: "ຕອບ​ໄປ​ທີ"
loadMore: "ໂຫຼດເພີ່ມເຕີມ"
showMore: "ໂຫຼດເພີ່ມເຕີມ"
showLess: "ປິດ"
youGotNewFollower: "ໄດ້ຕິດຕາມທ່ານ"
receiveFollowRequest: "ປະຕິບັດຕາມຄໍາຮ້ອງຂໍທີ່ໄດ້ຮັບ"
followRequestAccepted: "ຜູ້ຕິດຕາມໄດ້ຍອມຮັບຄໍາຮ້ອງຂໍຂອງທ່ານ"
mention: "ໄດ້ກ່າວມາ"
mentions: "ກ່າວເຖິງ"
directNotes: "ໂດຍກົງຫມາຍເຫດ"
importAndExport: "ນໍາເຂົ້າ / ສົ່ງອອກ"
import: "ນຳເຂົ້າ"
export: "ນຳອອກ"
files: "ໄຟລ໌"
download: "ດາວໂຫລດ"
driveFileDeleteConfirm: "ທ່ານແນ່ໃຈບໍ່ວ່າຕ້ອງການລຶບໄຟລ໌ \"{name}\"? ບັນທຶກທີ່ມີໄຟລ໌ແນບນີ້ຈະຖືກລຶບຖິ້ມ"
unfollowConfirm: "ທ່ານແນ່ໃຈບໍ່ວ່າຕ້ອງການເຊົາຕິດຕາມ {name}?"
exportRequested: "ໃນເວລາທີ່ທ່ານໄດ້ຮ້ອງຂໍການສົ່ງອອກ ມັນອາດຈະໃຊ້ເວລາບາງເວລາ ແລະມັນຈະຖືກເພີ່ມໃສ່ drive ຂອງທ່ານເມື່ອມັນສຳເລັດແລ້ວ"
importRequested: "ໃນເວລາທີ່ທ່ານໄດ້ຮ້ອງຂໍການນໍາເຂົ້າ ມັນອາດຈະໃຊ້ເວລາບາງເວລາ"
lists: "ລາຍການ"
noLists: "ທ່ານ​ບໍ່​ມີ​ລາຍ​ການ​ໃດໆ​"
note: "ບັນທຶກ"
notes: "ບັນທຶກ"
following: "ກຳລັງຕິດຕາມ"
followers: "ຜູ້ຕິດຕາມ"
followsYou: "ຕິດ​ຕາມ​ເຈົ້າ"
createList: "ສ້າງລາຍຊື່"
manageLists: "ການບໍລິຫານບັນຊີລາຍການ"
error: "ຂໍ້ຜິດພາດ"
somethingHappened: "​ອຸຍ, ມີ​ບາງ​ຢ່າງ​ຜິ​ດ​ພາດ"
retry: "ລອງໃຫມ່"
pageLoadError: "ເກີດຄວາມຜິດພາດໃນການໂຫລດໜ້ານີ້"
pageLoadErrorDescription: "ປົກກະຕິແລ້ວມັນເກີດຈາກຄວາມຜິດພາດເຄືອຂ່າຍ ຫຼື cache ຂອງຕົວທ່ອງເວັບ ລອງລຶບລ້າງແຄດແລ້ວລອງໃໝ່ພາຍຫຼັງສອງສາມນາທີ"
serverIsDead: "ເຊີບເວີນີ້ບໍ່ຕອບສະໜອງ ກະລຸນາລໍຖ້າຈັກໜ່ອຍແລ້ວລອງໃໝ່ອີກຄັ້ງ"
youShouldUpgradeClient: "ເພື່ອເບິ່ງໜ້ານີ້, ກະລຸນາໂຫຼດຂໍ້ມູນຄືນໃໝ່ເພື່ອອັບເດດລູກຄ້າຂອງທ່ານ"
enterListName: "ໃສ່ຊື່ສຳລັບລາຍຊື່"
privacy: "ຄວາມເປັນສ່ວນຕົວ"
makeFollowManuallyApprove: "ປະຕິບັດຕາມການຮ້ອງຂໍຮຽກຮ້ອງໃຫ້ມີການອະນຸມັດ"
defaultNoteVisibility: "ເປັນຄ່າເລີ່ມຕົ້ນ"
follow: "ກຳລັງຕິດຕາມ"
followRequest: "ສົ່ງ​ການ​ຮ້ອງ​ຂໍ​ປະ​ຕິ​ບ​ຕາມ​"
followRequests: "ປະຕິບັດຕາມຄໍາຮ້ອງຂໍ"
unfollow: "ເຊົາຕິດຕາມ"
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: "ລະຫັດຜ່ານ"
clearCache: "ລຶບລ້າງແຄສ"
user: "ຜູ້ໃຊ້ຕ່າງໆ"
searchByGoogle: "ຄົ້ນຫາ"
file: "ໄຟລ໌"
_email:
_follow:
title: "ໄດ້ຕິດຕາມທ່ານ"
_mfm:
mention: "ໄດ້ກ່າວມາ"
quote: "ລວມຂໍ້ຄວາມອ້າງອີງ"
emoji: "ອີໂມຈິແບບກຳນົດເອງ"
search: "ຄົ້ນຫາ"
_theme:
keys:
mention: "ໄດ້ກ່າວມາ"
renote: "Renote"
_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"
_deck:
_columns:
notifications: "ການແຈ້ງເຕືອນ"
tl: "​ເສັ້ນກຳ​ນົດ​ເວ​ລາ​"
list: "ລາຍການ"
channel: "ຊ່ອງ"
mentions: "ກ່າວເຖິງ"

View File

@@ -129,6 +129,7 @@ unblockConfirm: "คุณแน่ใจแล้วเหรอ? ว่าต
suspendConfirm: "นายแน่ใจแล้วเหรอว่าต้องการระงับบัญชีนี้อ่ะ?"
unsuspendConfirm: "นายแน่ใจแล้วหรอ? ว่าต้องการยกเลิกการระงับบัญชีนี้"
selectList: "เลือกรายการ"
selectChannel: "เลือกแชนแนล"
selectAntenna: "เลือกเสาอากาศ"
selectWidget: "เลือกวิดเจ็ต"
editWidgets: "แก้ไขวิดเจ็ต"
@@ -939,6 +940,8 @@ cannotPerformTemporaryDescription: "การดําเนินการน
preset: "พรีเซ็ต"
selectFromPresets: "เลือกจากการพรีเซ็ต"
achievements: "ความสำเร็จ"
gotInvalidResponseError: "การตอบสนองเซิร์ฟเวอร์ไม่ถูกต้อง"
gotInvalidResponseErrorDescription: "เซิร์ฟเวอร์อาจไม่สามารถเข้าถึงได้หรืออาจจะกำลังอยู่ในระหว่างปรับปรุง กรุณาลองใหม่อีกครั้งในภายหลังนะคะ"
_achievements:
earnedAt: "ได้รับเมื่อ"
_types:
@@ -1593,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: "โน้ตจากผู้ใช้ที่ติดตาม"

View File

@@ -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: "已关注用户的帖子"

View File

@@ -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:
@@ -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: "來自已追隨使用者的貼文"

View File

@@ -1,12 +1,12 @@
{
"name": "misskey",
"version": "13.5.4",
"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",

View File

@@ -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',

View File

@@ -107,6 +107,7 @@ onMounted(() => {
}
.iconFrame {
position: relative;
width: 58px;
height: 58px;
padding: 6px;

View File

@@ -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>

View File

@@ -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,

View File

@@ -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>

View File

@@ -134,6 +134,9 @@ const previewable = (file: misskey.entities.DriveFile): boolean => {
display: grid;
grid-gap: 8px;
// for webkit
height: 100%;
&.n1 {
aspect-ratio: 16/9;
grid-template-rows: 1fr;

View File

@@ -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"/>

View File

@@ -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;
}
}

View File

@@ -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, {

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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) {

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}