Compare commits
20 Commits
2024.9.0-a
...
2024.10.0-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e97b7fe2a1 | ||
|
|
87617dca39 | ||
|
|
9dc058189e | ||
|
|
83db116c46 | ||
|
|
d3e2b59f53 | ||
|
|
1074d625ed | ||
|
|
6dde457452 | ||
|
|
a25d83f249 | ||
|
|
6fd4de246c | ||
|
|
e9519b02fb | ||
|
|
b6578861ac | ||
|
|
ca8cc015b0 | ||
|
|
4f34a4e4d8 | ||
|
|
781e64aa7f | ||
|
|
d6e1f022d4 | ||
|
|
2ea49703f6 | ||
|
|
1184436461 | ||
|
|
0871156780 | ||
|
|
088707c114 | ||
|
|
15f2e1425c |
@@ -21,6 +21,7 @@ jobs:
|
||||
uses: actions/checkout@v4.1.1
|
||||
with:
|
||||
submodules: true
|
||||
persist-credentials: false
|
||||
ref: refs/pull/${{ github.event.pull_request.number }}/merge
|
||||
|
||||
- name: setup pnpm
|
||||
@@ -57,7 +58,7 @@ jobs:
|
||||
name: generated-misskey-js
|
||||
path: packages/misskey-js/generator/built/autogen
|
||||
|
||||
# pull_request_target safety: permissions: read-all, and there are no secrets used in this job
|
||||
# pull_request_target safety: permissions: read-all, and no user codes are executed
|
||||
get-actual-misskey-js:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
@@ -68,6 +69,7 @@ jobs:
|
||||
uses: actions/checkout@v4.1.1
|
||||
with:
|
||||
submodules: true
|
||||
persist-credentials: false
|
||||
ref: refs/pull/${{ github.event.pull_request.number }}/merge
|
||||
|
||||
- name: Upload From Merged
|
||||
@@ -131,3 +133,7 @@ jobs:
|
||||
mode: delete
|
||||
message: "Thank you!"
|
||||
create_if_not_exists: false
|
||||
|
||||
- name: Make failure if changes are detected
|
||||
if: steps.check-changes.outputs.changes == 'true'
|
||||
run: exit 1
|
||||
|
||||
13
CHANGELOG.md
13
CHANGELOG.md
@@ -1,3 +1,15 @@
|
||||
## 2024.10.0
|
||||
|
||||
### General
|
||||
- Enhance: セキュリティ向上のため、サインイン時もCAPTCHAを求めるようになりました
|
||||
|
||||
### Client
|
||||
- Enhance: フォロワーへのメッセージ欄のデザイン改良
|
||||
|
||||
### Server
|
||||
- Enhance: セキュリティ向上のため、ログイン時にメール通知を行うように
|
||||
|
||||
|
||||
## 2024.9.0
|
||||
|
||||
### General
|
||||
@@ -22,6 +34,7 @@
|
||||
- Enhance: Play編集画面の項目の並びを少しリデザイン
|
||||
- Enhance: 各種メニューをドロワー表示するかどうか設定可能に
|
||||
- Enhance: AiScriptのMk:C:containerのオプションに`borderStyle`と`borderRadius`を追加
|
||||
- Enhance: CWでも絵文字をクリックしてメニューを表示できるように
|
||||
- Fix: サーバーメトリクスが2つ以上あるとリロード直後の表示がおかしくなる問題を修正
|
||||
- Fix: コントロールパネル内のAp requests内のチャートの表示がおかしかった問題を修正
|
||||
- Fix: 月の違う同じ日はセパレータが表示されないのを修正
|
||||
|
||||
@@ -451,7 +451,6 @@ or: "অথবা"
|
||||
language: "ভাষা"
|
||||
uiLanguage: "UI এর ভাষা"
|
||||
aboutX: "{x} সম্পর্কে"
|
||||
disableDrawer: "ড্রয়ার মেনু প্রদর্শন করবেন না"
|
||||
noHistory: "কোনো ইতিহাস নেই"
|
||||
signinHistory: "প্রবেশ করার ইতিহাস"
|
||||
doing: "প্রক্রিয়া করছে..."
|
||||
|
||||
@@ -509,7 +509,6 @@ uiLanguage: "Idioma de l'interfície"
|
||||
aboutX: "Respecte a {x}"
|
||||
emojiStyle: "Estil d'emoji"
|
||||
native: "Nadiu"
|
||||
disableDrawer: "No mostrar els menús en calaixos"
|
||||
showNoteActionsOnlyHover: "Només mostra accions de la nota en passar amb el cursor"
|
||||
showReactionsCount: "Mostra el nombre de reaccions a les publicacions"
|
||||
noHistory: "No hi ha un registre previ"
|
||||
|
||||
@@ -471,7 +471,6 @@ uiLanguage: "Jazyk uživatelského rozhraní"
|
||||
aboutX: "O {x}"
|
||||
emojiStyle: "Styl emoji"
|
||||
native: "Výchozí"
|
||||
disableDrawer: "Nepoužívat šuplíkové menu"
|
||||
showNoteActionsOnlyHover: "Zobrazit akce poznámky jenom při naběhnutí myši"
|
||||
noHistory: "Žádná historie"
|
||||
signinHistory: "Historie přihlášení"
|
||||
|
||||
@@ -491,7 +491,6 @@ uiLanguage: "Sprache der Benutzeroberfläche"
|
||||
aboutX: "Über {x}"
|
||||
emojiStyle: "Emoji-Stil"
|
||||
native: "Nativ"
|
||||
disableDrawer: "Keine ausfahrbaren Menüs verwenden"
|
||||
showNoteActionsOnlyHover: "Notizmenü nur bei Mouseover anzeigen"
|
||||
noHistory: "Kein Verlauf gefunden"
|
||||
signinHistory: "Anmeldungsverlauf"
|
||||
|
||||
@@ -509,7 +509,6 @@ uiLanguage: "User interface language"
|
||||
aboutX: "About {x}"
|
||||
emojiStyle: "Emoji style"
|
||||
native: "Native"
|
||||
disableDrawer: "Don't use drawer-style menus"
|
||||
showNoteActionsOnlyHover: "Only show note actions on hover"
|
||||
showReactionsCount: "See the number of reactions in notes"
|
||||
noHistory: "No history available"
|
||||
|
||||
@@ -502,7 +502,6 @@ uiLanguage: "Idioma de visualización de la interfaz"
|
||||
aboutX: "Acerca de {x}"
|
||||
emojiStyle: "Estilo de emoji"
|
||||
native: "Nativo"
|
||||
disableDrawer: "No mostrar los menús en cajones"
|
||||
showNoteActionsOnlyHover: "Mostrar acciones de la nota sólo al pasar el cursor"
|
||||
showReactionsCount: "Mostrar el número de reacciones en las notas"
|
||||
noHistory: "No hay datos en el historial"
|
||||
|
||||
@@ -493,7 +493,6 @@ uiLanguage: "Langue d’affichage de l’interface"
|
||||
aboutX: "À propos de {x}"
|
||||
emojiStyle: "Style des émojis"
|
||||
native: "Natif"
|
||||
disableDrawer: "Les menus ne s'affichent pas dans le tiroir"
|
||||
showNoteActionsOnlyHover: "Afficher les actions de note uniquement au survol"
|
||||
showReactionsCount: "Afficher le nombre de réactions des notes"
|
||||
noHistory: "Pas d'historique"
|
||||
|
||||
@@ -504,7 +504,6 @@ uiLanguage: "Bahasa antarmuka pengguna"
|
||||
aboutX: "Tentang {x}"
|
||||
emojiStyle: "Gaya emoji"
|
||||
native: "Native"
|
||||
disableDrawer: "Jangan gunakan menu bergaya laci"
|
||||
showNoteActionsOnlyHover: "Hanya tampilkan aksi catatan saat ditunjuk"
|
||||
showReactionsCount: "Lihat jumlah reaksi dalam catatan"
|
||||
noHistory: "Tidak ada riwayat"
|
||||
|
||||
12
locales/index.d.ts
vendored
12
locales/index.d.ts
vendored
@@ -5148,6 +5148,10 @@ export interface Locale extends ILocale {
|
||||
* パスキーの検証に成功しましたが、パスワードレスログインが無効になっています。
|
||||
*/
|
||||
"passkeyVerificationSucceededButPasswordlessLoginDisabled": string;
|
||||
/**
|
||||
* フォロワーへのメッセージ
|
||||
*/
|
||||
"messageToFollower": string;
|
||||
"_delivery": {
|
||||
/**
|
||||
* 配信状態
|
||||
@@ -9281,6 +9285,10 @@ export interface Locale extends ILocale {
|
||||
* {x}のエクスポートが完了しました
|
||||
*/
|
||||
"exportOfXCompleted": ParameterizedString<"x">;
|
||||
/**
|
||||
* ログインがありました
|
||||
*/
|
||||
"login": string;
|
||||
"_types": {
|
||||
/**
|
||||
* すべて
|
||||
@@ -9338,6 +9346,10 @@ export interface Locale extends ILocale {
|
||||
* エクスポートが完了した
|
||||
*/
|
||||
"exportCompleted": string;
|
||||
/**
|
||||
* ログイン
|
||||
*/
|
||||
"login": string;
|
||||
/**
|
||||
* 通知のテスト
|
||||
*/
|
||||
|
||||
@@ -334,6 +334,7 @@ renameFolder: "Rinomina cartella"
|
||||
deleteFolder: "Elimina cartella"
|
||||
folder: "Cartella"
|
||||
addFile: "Allega"
|
||||
showFile: "Visualizza file"
|
||||
emptyDrive: "Il Drive è vuoto"
|
||||
emptyFolder: "La cartella è vuota"
|
||||
unableToDelete: "Eliminazione impossibile"
|
||||
@@ -509,7 +510,10 @@ uiLanguage: "Lingua di visualizzazione dell'interfaccia"
|
||||
aboutX: "Informazioni su {x}"
|
||||
emojiStyle: "Stile emoji"
|
||||
native: "Nativo"
|
||||
disableDrawer: "Non mostrare il menù sul drawer"
|
||||
menuStyle: "Stile menu"
|
||||
style: "Stile"
|
||||
drawer: "Drawer"
|
||||
popup: "Popup"
|
||||
showNoteActionsOnlyHover: "Mostra le azioni delle Note solo al passaggio del mouse"
|
||||
showReactionsCount: "Visualizza il numero di reazioni su una nota"
|
||||
noHistory: "Nessuna cronologia"
|
||||
@@ -1270,6 +1274,13 @@ genEmbedCode: "Ottieni il codice di incorporamento"
|
||||
noteOfThisUser: "Elenco di Note di questo profilo"
|
||||
clipNoteLimitExceeded: "Non è possibile aggiungere ulteriori Note a questa Clip."
|
||||
performance: "Prestazioni"
|
||||
modified: "Modificato"
|
||||
discard: "Scarta"
|
||||
thereAreNChanges: "Ci sono {n} cambiamenti"
|
||||
signinWithPasskey: "Accedi con passkey"
|
||||
unknownWebAuthnKey: "Questa è una passkey sconosciuta."
|
||||
passkeyVerificationFailed: "La verifica della passkey non è riuscita."
|
||||
passkeyVerificationSucceededButPasswordlessLoginDisabled: "La verifica della passkey è riuscita, ma l'accesso senza password è disabilitato."
|
||||
_delivery:
|
||||
status: "Stato della consegna"
|
||||
stop: "Sospensione"
|
||||
@@ -2375,6 +2386,7 @@ _notification:
|
||||
renotedBySomeUsers: "{n} Rinota"
|
||||
followedBySomeUsers: "{n} follower"
|
||||
flushNotification: "Azzera le notifiche"
|
||||
exportOfXCompleted: "Abbiamo completato l'esportazione di {x}"
|
||||
_types:
|
||||
all: "Tutto"
|
||||
note: "Nuove Note"
|
||||
@@ -2389,6 +2401,8 @@ _notification:
|
||||
followRequestAccepted: "Richiesta di follow accettata"
|
||||
roleAssigned: "Ruolo concesso"
|
||||
achievementEarned: "Risultato raggiunto"
|
||||
exportCompleted: "Esportazione completata"
|
||||
test: "Prova la notifica"
|
||||
app: "Notifiche da applicazioni"
|
||||
_actions:
|
||||
followBack: "Segui"
|
||||
|
||||
@@ -1283,6 +1283,7 @@ signinWithPasskey: "パスキーでログイン"
|
||||
unknownWebAuthnKey: "登録されていないパスキーです。"
|
||||
passkeyVerificationFailed: "パスキーの検証に失敗しました。"
|
||||
passkeyVerificationSucceededButPasswordlessLoginDisabled: "パスキーの検証に成功しましたが、パスワードレスログインが無効になっています。"
|
||||
messageToFollower: "フォロワーへのメッセージ"
|
||||
|
||||
_delivery:
|
||||
status: "配信状態"
|
||||
@@ -2450,6 +2451,7 @@ _notification:
|
||||
followedBySomeUsers: "{n}人にフォローされました"
|
||||
flushNotification: "通知の履歴をリセットする"
|
||||
exportOfXCompleted: "{x}のエクスポートが完了しました"
|
||||
login: "ログインがありました"
|
||||
|
||||
_types:
|
||||
all: "すべて"
|
||||
@@ -2466,6 +2468,7 @@ _notification:
|
||||
roleAssigned: "ロールが付与された"
|
||||
achievementEarned: "実績の獲得"
|
||||
exportCompleted: "エクスポートが完了した"
|
||||
login: "ログイン"
|
||||
test: "通知のテスト"
|
||||
app: "連携アプリからの通知"
|
||||
|
||||
|
||||
@@ -509,7 +509,6 @@ uiLanguage: "UIの表示言語"
|
||||
aboutX: "{x}について"
|
||||
emojiStyle: "絵文字のスタイル"
|
||||
native: "ネイティブ"
|
||||
disableDrawer: "メニューをドロワーで表示せえへん"
|
||||
showNoteActionsOnlyHover: "ノートの操作部をホバー時のみ表示するで"
|
||||
showReactionsCount: "ノートのリアクション数を表示する"
|
||||
noHistory: "履歴はないわ。"
|
||||
|
||||
@@ -476,7 +476,6 @@ uiLanguage: "UI 표시 언어"
|
||||
aboutX: "{x}에 대해서"
|
||||
emojiStyle: "이모지 모양"
|
||||
native: "기본"
|
||||
disableDrawer: "드로어 메뉴 쓰지 않기"
|
||||
showNoteActionsOnlyHover: "마우스 올맀을 때만 노트 액션 버턴 보이기"
|
||||
noHistory: "기록이 없십니다"
|
||||
signinHistory: "로그인 기록"
|
||||
|
||||
@@ -236,6 +236,8 @@ silencedInstances: "사일런스한 서버"
|
||||
silencedInstancesDescription: "사일런스하려는 서버의 호스트명을 한 줄에 하나씩 입력합니다. 사일런스된 서버에 소속된 유저는 모두 '사일런스'된 상태로 취급되며, 이 서버로부터의 팔로우가 프로필 설정과 무관하게 승인제로 변경되고, 팔로워가 아닌 로컬 유저에게는 멘션할 수 없게 됩니다. 정지된 서버에는 적용되지 않습니다."
|
||||
mediaSilencedInstances: "미디어를 사일런스한 서버"
|
||||
mediaSilencedInstancesDescription: "미디어를 사일런스 하려는 서버의 호스트를 한 줄에 하나씩 입력합니다. 미디어가 사일런스된 서버의 유저가 업로드한 파일은 모두 민감한 미디어로 처리되며, 커스텀 이모지를 사용할 수 없게 됩니다. 또한, 차단한 인스턴스에는 적용되지 않습니다."
|
||||
federationAllowedHosts: "연합을 허가하는 서버"
|
||||
federationAllowedHostsDescription: "연합을 허가하는 서버의 호스트를 엔터로 구분해서 설정합니다."
|
||||
muteAndBlock: "뮤트 및 차단"
|
||||
mutedUsers: "뮤트한 유저"
|
||||
blockedUsers: "차단한 유저"
|
||||
@@ -334,6 +336,7 @@ renameFolder: "폴더 이름 바꾸기"
|
||||
deleteFolder: "폴더 삭제"
|
||||
folder: "폴더"
|
||||
addFile: "파일 추가"
|
||||
showFile: "파일 표시하기"
|
||||
emptyDrive: "드라이브가 비어 있습니다"
|
||||
emptyFolder: "폴더가 비어 있습니다"
|
||||
unableToDelete: "삭제할 수 없습니다"
|
||||
@@ -509,7 +512,10 @@ uiLanguage: "UI 표시 언어"
|
||||
aboutX: "{x}에 대하여"
|
||||
emojiStyle: "이모지 스타일"
|
||||
native: "기본"
|
||||
disableDrawer: "드로어 메뉴를 사용하지 않기"
|
||||
menuStyle: "메뉴 스타일"
|
||||
style: "스타일"
|
||||
drawer: "서랍"
|
||||
popup: "팝업"
|
||||
showNoteActionsOnlyHover: "마우스가 올라간 때에만 노트 동작 버튼을 표시하기"
|
||||
showReactionsCount: "노트의 반응 수를 표시하기"
|
||||
noHistory: "기록이 없습니다"
|
||||
@@ -1273,6 +1279,10 @@ performance: "퍼포먼스"
|
||||
modified: "변경 있음"
|
||||
discard: "파기"
|
||||
thereAreNChanges: "{n}건 변경이 있습니다."
|
||||
signinWithPasskey: "패스키로 로그인"
|
||||
unknownWebAuthnKey: "등록되지 않은 패스키입니다."
|
||||
passkeyVerificationFailed: "패스키 검증을 실패했습니다."
|
||||
passkeyVerificationSucceededButPasswordlessLoginDisabled: "패스키를 검증했으나, 비밀번호 없이 로그인하기가 꺼져 있습니다."
|
||||
_delivery:
|
||||
status: "전송 상태"
|
||||
stop: "정지됨"
|
||||
@@ -2240,6 +2250,9 @@ _profile:
|
||||
changeBanner: "배너 이미지 변경"
|
||||
verifiedLinkDescription: "내용에 자신의 프로필로 향하는 링크가 포함된 페이지의 URL을 삽입하면 소유자 인증 마크가 표시됩니다."
|
||||
avatarDecorationMax: "최대 {max}개까지 장식을 할 수 있습니다."
|
||||
followedMessage: "팔로우 받았을 때 메시지"
|
||||
followedMessageDescription: "팔로우 받았을 때 상대방에게 보여줄 단문 메시지를 설정할 수 있습니다."
|
||||
followedMessageDescriptionForLockedAccount: "팔로우를 승인제로 한 경우, 팔로우 요청을 수락했을 때 보여줍니다."
|
||||
_exportOrImport:
|
||||
allNotes: "모든 노트"
|
||||
favoritedNotes: "즐겨찾기한 노트"
|
||||
@@ -2378,6 +2391,7 @@ _notification:
|
||||
renotedBySomeUsers: "{n}명이 리노트했습니다"
|
||||
followedBySomeUsers: "{n}명에게 팔로우됨"
|
||||
flushNotification: "알림 이력을 초기화"
|
||||
exportOfXCompleted: "{x} 추출에 성공했습니다."
|
||||
_types:
|
||||
all: "전부"
|
||||
note: "사용자의 새 글"
|
||||
@@ -2392,6 +2406,8 @@ _notification:
|
||||
followRequestAccepted: "팔로우 요청이 승인되었을 때"
|
||||
roleAssigned: "역할이 부여 됨"
|
||||
achievementEarned: "도전 과제 획득"
|
||||
exportCompleted: "추출을 성공함"
|
||||
test: "알림 테스트"
|
||||
app: "연동된 앱을 통한 알림"
|
||||
_actions:
|
||||
followBack: "팔로우"
|
||||
|
||||
@@ -492,7 +492,6 @@ uiLanguage: "Język wyświetlania UI"
|
||||
aboutX: "O {x}"
|
||||
emojiStyle: "Styl emoji"
|
||||
native: "Natywny"
|
||||
disableDrawer: "Nie używaj menu w stylu szuflady"
|
||||
showNoteActionsOnlyHover: "Pokazuj akcje notatek tylko po najechaniu myszką"
|
||||
showReactionsCount: "Wyświetl liczbę reakcji na notatkę"
|
||||
noHistory: "Brak historii"
|
||||
|
||||
@@ -509,7 +509,6 @@ uiLanguage: "Idioma de exibição da interface "
|
||||
aboutX: "Sobre {x}"
|
||||
emojiStyle: "Estilo de emojis"
|
||||
native: "Nativo"
|
||||
disableDrawer: "Não mostrar o menu em formato de gaveta"
|
||||
showNoteActionsOnlyHover: "Exibir as ações da nota somente ao passar o cursor sobre ela"
|
||||
showReactionsCount: "Ver o número de reações nas notas"
|
||||
noHistory: "Ainda não há histórico"
|
||||
|
||||
@@ -453,7 +453,6 @@ or: "Sau"
|
||||
language: "Limbă"
|
||||
uiLanguage: "Limba interfeței"
|
||||
aboutX: "Despre {x}"
|
||||
disableDrawer: "Nu folosi meniuri în stil sertar"
|
||||
noHistory: "Nu există istoric"
|
||||
signinHistory: "Istoric autentificări"
|
||||
doing: "Se procesează..."
|
||||
|
||||
@@ -503,7 +503,6 @@ uiLanguage: "Язык интерфейса"
|
||||
aboutX: "Описание {x}"
|
||||
emojiStyle: "Стиль эмодзи"
|
||||
native: "Системные"
|
||||
disableDrawer: "Не использовать выдвижные меню"
|
||||
showNoteActionsOnlyHover: "Показывать кнопки у заметок только при наведении"
|
||||
showReactionsCount: "Видеть количество реакций на заметках"
|
||||
noHistory: "История пока пуста"
|
||||
|
||||
@@ -454,7 +454,6 @@ uiLanguage: "Jazyk používateľského prostredia"
|
||||
aboutX: "O {x}"
|
||||
emojiStyle: "Štýl emoji"
|
||||
native: "Natívne"
|
||||
disableDrawer: "Nepoužívať šuflíkové menu"
|
||||
showNoteActionsOnlyHover: "Ovládacie prvky poznámky sa zobrazujú len po nabehnutí myši"
|
||||
noHistory: "Žiadna história"
|
||||
signinHistory: "História prihlásení"
|
||||
|
||||
@@ -509,7 +509,6 @@ uiLanguage: "ภาษาอินเทอร์เฟซผู้ใช้ง
|
||||
aboutX: "เกี่ยวกับ {x}"
|
||||
emojiStyle: "สไตล์ของเอโมจิ"
|
||||
native: "ภาษาแม่"
|
||||
disableDrawer: "ไม่แสดงเมนูในรูปแบบลิ้นชัก"
|
||||
showNoteActionsOnlyHover: "แสดงการดำเนินการโน้ตเมื่อโฮเวอร์(วางเมาส์เหนือ)เท่านั้น"
|
||||
showReactionsCount: "แสดงจำนวนรีแอกชั่นในโน้ต"
|
||||
noHistory: "ไม่มีประวัติ"
|
||||
|
||||
@@ -452,7 +452,6 @@ language: "Мова"
|
||||
uiLanguage: "Мова інтерфейсу"
|
||||
aboutX: "Про {x}"
|
||||
native: "місцевий"
|
||||
disableDrawer: "Не використовувати висувні меню"
|
||||
noHistory: "Історія порожня"
|
||||
signinHistory: "Історія входів"
|
||||
enableAdvancedMfm: "Увімкнути розширений MFM"
|
||||
|
||||
@@ -471,7 +471,6 @@ uiLanguage: "Interfeys tili"
|
||||
aboutX: "{x} haqida"
|
||||
emojiStyle: "Emoji ko'rinishi"
|
||||
native: "Mahalliy"
|
||||
disableDrawer: "Slayd menyusidan foydalanmang"
|
||||
showNoteActionsOnlyHover: "Eslatma amallarini faqat sichqonchani olib borganda ko‘rsatish"
|
||||
noHistory: "Tarix yo'q"
|
||||
signinHistory: "kirish tarixi"
|
||||
|
||||
@@ -486,7 +486,6 @@ uiLanguage: "Ngôn ngữ giao diện"
|
||||
aboutX: "Giới thiệu {x}"
|
||||
emojiStyle: "Kiểu cách Emoji"
|
||||
native: "Bản xứ"
|
||||
disableDrawer: "Không dùng menu thanh bên"
|
||||
showNoteActionsOnlyHover: "Chỉ hiển thị các hành động ghi chú khi di chuột"
|
||||
noHistory: "Không có dữ liệu"
|
||||
signinHistory: "Lịch sử đăng nhập"
|
||||
|
||||
@@ -334,6 +334,7 @@ renameFolder: "重命名文件夹"
|
||||
deleteFolder: "删除文件夹"
|
||||
folder: "文件夹"
|
||||
addFile: "添加文件"
|
||||
showFile: "显示文件"
|
||||
emptyDrive: "网盘中无文件"
|
||||
emptyFolder: "此文件夹中无文件"
|
||||
unableToDelete: "无法删除"
|
||||
@@ -509,7 +510,9 @@ uiLanguage: "显示语言"
|
||||
aboutX: "关于 {x}"
|
||||
emojiStyle: "表情符号的样式"
|
||||
native: "原生"
|
||||
disableDrawer: "不显示抽屉菜单"
|
||||
menuStyle: "菜单样式"
|
||||
style: "样式"
|
||||
popup: "弹窗"
|
||||
showNoteActionsOnlyHover: "仅在悬停时显示帖子操作"
|
||||
showReactionsCount: "显示帖子的回应数"
|
||||
noHistory: "没有历史记录"
|
||||
@@ -1270,6 +1273,10 @@ genEmbedCode: "生成嵌入代码"
|
||||
noteOfThisUser: "此用户的帖子"
|
||||
clipNoteLimitExceeded: "无法再往此便签内添加更多帖子"
|
||||
performance: "性能"
|
||||
signinWithPasskey: "使用通行密钥登录"
|
||||
unknownWebAuthnKey: "此通行密钥未注册。"
|
||||
passkeyVerificationFailed: "验证通行密钥失败。"
|
||||
passkeyVerificationSucceededButPasswordlessLoginDisabled: "通行密钥验证成功,但账户未开启无密码登录。"
|
||||
_delivery:
|
||||
status: "投递状态"
|
||||
stop: "停止投递"
|
||||
@@ -2375,6 +2382,7 @@ _notification:
|
||||
renotedBySomeUsers: "{n} 人转发了"
|
||||
followedBySomeUsers: "被 {n} 人关注"
|
||||
flushNotification: "重置通知历史"
|
||||
exportOfXCompleted: "已完成 {x} 个导出"
|
||||
_types:
|
||||
all: "全部"
|
||||
note: "用户的新帖子"
|
||||
@@ -2389,6 +2397,8 @@ _notification:
|
||||
followRequestAccepted: "关注请求已通过"
|
||||
roleAssigned: "授予的角色"
|
||||
achievementEarned: "取得的成就"
|
||||
exportCompleted: "已完成导出"
|
||||
test: "测试通知"
|
||||
app: "关联应用的通知"
|
||||
_actions:
|
||||
followBack: "回关"
|
||||
|
||||
@@ -236,6 +236,8 @@ silencedInstances: "被禁言的伺服器"
|
||||
silencedInstancesDescription: "設定要禁言的伺服器主機名稱,以換行分隔。隸屬於禁言伺服器的所有帳戶都將被視為「禁言帳戶」,只能發出「追隨請求」,而且無法提及未追隨的本地帳戶。這不會影響已封鎖的實例。"
|
||||
mediaSilencedInstances: "媒體被禁言的伺服器"
|
||||
mediaSilencedInstancesDescription: "設定您想要對媒體設定禁言的伺服器,以換行符號區隔。來自被媒體禁言的伺服器所屬帳戶的所有檔案都會被視為敏感檔案,且自訂表情符號不能使用。被封鎖的伺服器不受影響。"
|
||||
federationAllowedHosts: "允許聯邦通訊的伺服器"
|
||||
federationAllowedHostsDescription: "設定允許聯邦通訊的伺服器主機,以換行符號分隔。"
|
||||
muteAndBlock: "靜音和封鎖"
|
||||
mutedUsers: "被靜音的使用者"
|
||||
blockedUsers: "被封鎖的使用者"
|
||||
@@ -334,6 +336,7 @@ renameFolder: "重新命名資料夾"
|
||||
deleteFolder: "刪除資料夾"
|
||||
folder: "資料夾"
|
||||
addFile: "加入附件"
|
||||
showFile: "瀏覽文件"
|
||||
emptyDrive: "雲端硬碟為空"
|
||||
emptyFolder: "資料夾為空"
|
||||
unableToDelete: "無法刪除"
|
||||
@@ -509,7 +512,10 @@ uiLanguage: "介面語言"
|
||||
aboutX: "關於{x}"
|
||||
emojiStyle: "表情符號的風格"
|
||||
native: "原生"
|
||||
disableDrawer: "不顯示下拉式選單"
|
||||
menuStyle: "選單風格"
|
||||
style: "風格"
|
||||
drawer: "側邊欄"
|
||||
popup: "彈出式視窗"
|
||||
showNoteActionsOnlyHover: "僅在游標停留時顯示貼文的操作選項"
|
||||
showReactionsCount: "顯示貼文的反應數目"
|
||||
noHistory: "沒有歷史紀錄"
|
||||
@@ -1273,6 +1279,10 @@ performance: "性能"
|
||||
modified: "已變更"
|
||||
discard: "取消"
|
||||
thereAreNChanges: "有 {n} 處的變更"
|
||||
signinWithPasskey: "使用密碼金鑰登入"
|
||||
unknownWebAuthnKey: "未註冊的金鑰。"
|
||||
passkeyVerificationFailed: "驗證金鑰失敗。"
|
||||
passkeyVerificationSucceededButPasswordlessLoginDisabled: "雖然驗證金鑰成功,但是無密碼登入的方式是停用的。"
|
||||
_delivery:
|
||||
status: "傳送狀態"
|
||||
stop: "停止發送"
|
||||
@@ -2240,6 +2250,9 @@ _profile:
|
||||
changeBanner: "變更橫幅圖像"
|
||||
verifiedLinkDescription: "如果輸入包含您個人資料的網站 URL,欄位旁邊將出現驗證圖示。"
|
||||
avatarDecorationMax: "最多可以設置 {max} 個裝飾。"
|
||||
followedMessage: "被追隨時的訊息"
|
||||
followedMessageDescription: "可以設定被追隨時顯示給對方的訊息。"
|
||||
followedMessageDescriptionForLockedAccount: "如果追隨是需要審核的話,在允許追隨請求之後顯示。"
|
||||
_exportOrImport:
|
||||
allNotes: "所有貼文"
|
||||
favoritedNotes: "「我的最愛」貼文"
|
||||
@@ -2378,6 +2391,7 @@ _notification:
|
||||
renotedBySomeUsers: "{n}人做了轉發"
|
||||
followedBySomeUsers: "被{n}人追隨了"
|
||||
flushNotification: "重置通知歷史紀錄"
|
||||
exportOfXCompleted: "{x} 的匯出已完成。"
|
||||
_types:
|
||||
all: "全部 "
|
||||
note: "使用者的最新貼文"
|
||||
@@ -2392,6 +2406,8 @@ _notification:
|
||||
followRequestAccepted: "追隨請求已接受"
|
||||
roleAssigned: "已授予角色"
|
||||
achievementEarned: "獲得成就"
|
||||
exportCompleted: "已完成匯出。"
|
||||
test: "通知測試"
|
||||
app: "應用程式通知"
|
||||
_actions:
|
||||
followBack: "追隨回去"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "misskey",
|
||||
"version": "2024.9.0-alpha.12",
|
||||
"version": "2024.10.0-alpha.0",
|
||||
"codename": "nasubi",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
BIN
packages/backend/assets/tabler-badges/login-2.png
Normal file
BIN
packages/backend/assets/tabler-badges/login-2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
@@ -67,24 +67,24 @@
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "3.620.0",
|
||||
"@aws-sdk/lib-storage": "3.620.0",
|
||||
"@bull-board/api": "5.23.0",
|
||||
"@bull-board/fastify": "5.23.0",
|
||||
"@bull-board/ui": "5.23.0",
|
||||
"@bull-board/api": "6.0.0",
|
||||
"@bull-board/fastify": "6.0.0",
|
||||
"@bull-board/ui": "6.0.0",
|
||||
"@discordapp/twemoji": "15.1.0",
|
||||
"@fastify/accepts": "5.0.0",
|
||||
"@fastify/cookie": "10.0.0",
|
||||
"@fastify/cors": "10.0.0",
|
||||
"@fastify/express": "4.0.0",
|
||||
"@fastify/accepts": "5.0.1",
|
||||
"@fastify/cookie": "10.0.1",
|
||||
"@fastify/cors": "10.0.1",
|
||||
"@fastify/express": "4.0.1",
|
||||
"@fastify/http-proxy": "10.0.0",
|
||||
"@fastify/multipart": "9.0.0",
|
||||
"@fastify/static": "8.0.0",
|
||||
"@fastify/view": "10.0.0",
|
||||
"@fastify/multipart": "9.0.1",
|
||||
"@fastify/static": "8.0.1",
|
||||
"@fastify/view": "10.0.1",
|
||||
"@misskey-dev/sharp-read-bmp": "1.2.0",
|
||||
"@misskey-dev/summaly": "5.1.0",
|
||||
"@napi-rs/canvas": "0.1.56",
|
||||
"@nestjs/common": "10.4.3",
|
||||
"@nestjs/core": "10.4.3",
|
||||
"@nestjs/testing": "10.4.3",
|
||||
"@nestjs/common": "10.4.4",
|
||||
"@nestjs/core": "10.4.4",
|
||||
"@nestjs/testing": "10.4.4",
|
||||
"@peertube/http-signature": "1.7.0",
|
||||
"@sentry/node": "8.20.0",
|
||||
"@sentry/profiling-node": "8.20.0",
|
||||
@@ -149,7 +149,7 @@
|
||||
"oauth2orize": "1.12.0",
|
||||
"oauth2orize-pkce": "0.1.2",
|
||||
"os-utils": "0.0.14",
|
||||
"otpauth": "9.3.2",
|
||||
"otpauth": "9.3.4",
|
||||
"parse5": "7.1.2",
|
||||
"pg": "8.13.0",
|
||||
"pkce-challenge": "4.1.0",
|
||||
@@ -187,7 +187,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@jest/globals": "29.7.0",
|
||||
"@nestjs/platform-express": "10.4.3",
|
||||
"@nestjs/platform-express": "10.4.4",
|
||||
"@simplewebauthn/types": "10.0.0",
|
||||
"@swc/jest": "0.2.36",
|
||||
"@types/accepts": "1.3.7",
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { userExportableEntities } from '@/types.js';
|
||||
import { MiUser } from './User.js';
|
||||
import { MiNote } from './Note.js';
|
||||
import { MiAccessToken } from './AccessToken.js';
|
||||
import { MiRole } from './Role.js';
|
||||
import { MiDriveFile } from './DriveFile.js';
|
||||
import { userExportableEntities } from '@/types.js';
|
||||
|
||||
export type MiNotification = {
|
||||
type: 'note';
|
||||
@@ -86,6 +86,10 @@ export type MiNotification = {
|
||||
createdAt: string;
|
||||
exportedEntity: typeof userExportableEntities[number];
|
||||
fileId: MiDriveFile['id'];
|
||||
} | {
|
||||
type: 'login';
|
||||
id: string;
|
||||
createdAt: string;
|
||||
} | {
|
||||
type: 'app';
|
||||
id: string;
|
||||
|
||||
@@ -322,6 +322,16 @@ export const packedNotificationSchema = {
|
||||
format: 'id',
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
...baseSchema.properties,
|
||||
type: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
enum: ['login'],
|
||||
},
|
||||
},
|
||||
}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
|
||||
@@ -9,6 +9,7 @@ import * as OTPAuth from 'otpauth';
|
||||
import { IsNull } from 'typeorm';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type {
|
||||
MiMeta,
|
||||
SigninsRepository,
|
||||
UserProfilesRepository,
|
||||
UsersRepository,
|
||||
@@ -20,6 +21,8 @@ import { IdService } from '@/core/IdService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { WebAuthnService } from '@/core/WebAuthnService.js';
|
||||
import { UserAuthService } from '@/core/UserAuthService.js';
|
||||
import { CaptchaService } from '@/core/CaptchaService.js';
|
||||
import { FastifyReplyError } from '@/misc/fastify-reply-error.js';
|
||||
import { RateLimiterService } from './RateLimiterService.js';
|
||||
import { SigninService } from './SigninService.js';
|
||||
import type { AuthenticationResponseJSON } from '@simplewebauthn/types';
|
||||
@@ -31,6 +34,9 @@ export class SigninApiService {
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
|
||||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.usersRepository)
|
||||
private usersRepository: UsersRepository,
|
||||
|
||||
@@ -45,6 +51,7 @@ export class SigninApiService {
|
||||
private signinService: SigninService,
|
||||
private userAuthService: UserAuthService,
|
||||
private webAuthnService: WebAuthnService,
|
||||
private captchaService: CaptchaService,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -56,6 +63,10 @@ export class SigninApiService {
|
||||
password: string;
|
||||
token?: string;
|
||||
credential?: AuthenticationResponseJSON;
|
||||
'hcaptcha-response'?: string;
|
||||
'g-recaptcha-response'?: string;
|
||||
'turnstile-response'?: string;
|
||||
'm-captcha-response'?: string;
|
||||
};
|
||||
}>,
|
||||
reply: FastifyReply,
|
||||
@@ -139,6 +150,32 @@ export class SigninApiService {
|
||||
};
|
||||
|
||||
if (!profile.twoFactorEnabled) {
|
||||
if (process.env.NODE_ENV !== 'test') {
|
||||
if (this.meta.enableHcaptcha && this.meta.hcaptchaSecretKey) {
|
||||
await this.captchaService.verifyHcaptcha(this.meta.hcaptchaSecretKey, body['hcaptcha-response']).catch(err => {
|
||||
throw new FastifyReplyError(400, err);
|
||||
});
|
||||
}
|
||||
|
||||
if (this.meta.enableMcaptcha && this.meta.mcaptchaSecretKey && this.meta.mcaptchaSitekey && this.meta.mcaptchaInstanceUrl) {
|
||||
await this.captchaService.verifyMcaptcha(this.meta.mcaptchaSecretKey, this.meta.mcaptchaSitekey, this.meta.mcaptchaInstanceUrl, body['m-captcha-response']).catch(err => {
|
||||
throw new FastifyReplyError(400, err);
|
||||
});
|
||||
}
|
||||
|
||||
if (this.meta.enableRecaptcha && this.meta.recaptchaSecretKey) {
|
||||
await this.captchaService.verifyRecaptcha(this.meta.recaptchaSecretKey, body['g-recaptcha-response']).catch(err => {
|
||||
throw new FastifyReplyError(400, err);
|
||||
});
|
||||
}
|
||||
|
||||
if (this.meta.enableTurnstile && this.meta.turnstileSecretKey) {
|
||||
await this.captchaService.verifyTurnstile(this.meta.turnstileSecretKey, body['turnstile-response']).catch(err => {
|
||||
throw new FastifyReplyError(400, err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (same) {
|
||||
return this.signinService.signin(request, reply, user);
|
||||
} else {
|
||||
|
||||
@@ -5,12 +5,14 @@
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { SigninsRepository } from '@/models/_.js';
|
||||
import type { SigninsRepository, UserProfilesRepository } from '@/models/_.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import type { MiLocalUser } from '@/models/User.js';
|
||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||
import { SigninEntityService } from '@/core/entities/SigninEntityService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { EmailService } from '@/core/EmailService.js';
|
||||
import { NotificationService } from '@/core/NotificationService.js';
|
||||
import type { FastifyRequest, FastifyReply } from 'fastify';
|
||||
|
||||
@Injectable()
|
||||
@@ -19,7 +21,12 @@ export class SigninService {
|
||||
@Inject(DI.signinsRepository)
|
||||
private signinsRepository: SigninsRepository,
|
||||
|
||||
@Inject(DI.userProfilesRepository)
|
||||
private userProfilesRepository: UserProfilesRepository,
|
||||
|
||||
private signinEntityService: SigninEntityService,
|
||||
private emailService: EmailService,
|
||||
private notificationService: NotificationService,
|
||||
private idService: IdService,
|
||||
private globalEventService: GlobalEventService,
|
||||
) {
|
||||
@@ -28,7 +35,8 @@ export class SigninService {
|
||||
@bindThis
|
||||
public signin(request: FastifyRequest, reply: FastifyReply, user: MiLocalUser) {
|
||||
setImmediate(async () => {
|
||||
// Append signin history
|
||||
this.notificationService.createNotification(user.id, 'login', {});
|
||||
|
||||
const record = await this.signinsRepository.insertOne({
|
||||
id: this.idService.gen(),
|
||||
userId: user.id,
|
||||
@@ -37,8 +45,14 @@ export class SigninService {
|
||||
success: true,
|
||||
});
|
||||
|
||||
// Publish signin event
|
||||
this.globalEventService.publishMainStream(user.id, 'signin', await this.signinEntityService.pack(record));
|
||||
|
||||
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id });
|
||||
if (profile.email && profile.emailVerified) {
|
||||
this.emailService.sendEmail(profile.email, 'New login / ログインがありました',
|
||||
'There is a new login. If you do not recognize this login, update the security status of your account, including changing your password. / 新しいログインがありました。このログインに心当たりがない場合は、パスワードを変更するなど、アカウントのセキュリティ状態を更新してください。',
|
||||
'There is a new login. If you do not recognize this login, update the security status of your account, including changing your password. / 新しいログインがありました。このログインに心当たりがない場合は、パスワードを変更するなど、アカウントのセキュリティ状態を更新してください。');
|
||||
}
|
||||
});
|
||||
|
||||
reply.code(200);
|
||||
|
||||
@@ -256,7 +256,7 @@ export class ClientServerService {
|
||||
});
|
||||
|
||||
bullBoardServerAdapter.setBasePath(bullBoardPath);
|
||||
//(fastify.register as any)(bullBoardServerAdapter.registerPlugin(), { prefix: bullBoardPath });
|
||||
(fastify.register as any)(bullBoardServerAdapter.registerPlugin(), { prefix: bullBoardPath });
|
||||
//#endregion
|
||||
|
||||
fastify.register(fastifyView, {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
* roleAssigned - ロールが付与された
|
||||
* achievementEarned - 実績を獲得
|
||||
* exportCompleted - エクスポートが完了
|
||||
* login - ログイン
|
||||
* app - アプリ通知
|
||||
* test - テスト通知(サーバー側)
|
||||
*/
|
||||
@@ -34,6 +35,7 @@ export const notificationTypes = [
|
||||
'roleAssigned',
|
||||
'achievementEarned',
|
||||
'exportCompleted',
|
||||
'login',
|
||||
'app',
|
||||
'test',
|
||||
] as const;
|
||||
|
||||
@@ -180,7 +180,6 @@ describe('Webリソース', () => {
|
||||
}));
|
||||
});
|
||||
|
||||
/* queueは一時的に無効化されている
|
||||
describe.each([{ path: '/queue' }])('$path', ({ path }) => {
|
||||
test('はログインしないとGETできない。', async () => await notOk({
|
||||
path,
|
||||
@@ -198,7 +197,6 @@ describe('Webリソース', () => {
|
||||
cookie: cookie(alice),
|
||||
}));
|
||||
});
|
||||
*/
|
||||
|
||||
describe.each([{ path: '/streaming' }])('$path', ({ path }) => {
|
||||
test('はGETできない。', async () => await notOk({
|
||||
|
||||
@@ -91,6 +91,11 @@ export function getConfig(): UserConfig {
|
||||
}
|
||||
},
|
||||
},
|
||||
preprocessorOptions: {
|
||||
scss: {
|
||||
api: 'modern-compiler',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
define: {
|
||||
|
||||
@@ -68,6 +68,7 @@ export const notificationTypes = [
|
||||
'roleAssigned',
|
||||
'achievementEarned',
|
||||
'exportCompleted',
|
||||
'login',
|
||||
'test',
|
||||
'app',
|
||||
] as const;
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
"rollup": "4.22.5",
|
||||
"sanitize-html": "2.13.0",
|
||||
"sass": "1.79.3",
|
||||
"shiki": "1.12.0",
|
||||
"shiki": "1.21.0",
|
||||
"strict-event-emitter-types": "2.0.0",
|
||||
"textarea-caret": "3.1.0",
|
||||
"three": "0.169.0",
|
||||
|
||||
100
packages/frontend/src/components/MkFukidashi.vue
Normal file
100
packages/frontend/src/components/MkFukidashi.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="[
|
||||
$style.root,
|
||||
tail === 'left' ? $style.left : $style.right,
|
||||
negativeMargin === true && $style.negativeMergin,
|
||||
shadow === true && $style.shadow,
|
||||
]"
|
||||
>
|
||||
<div :class="$style.bg">
|
||||
<svg v-if="tail !== 'none'" :class="$style.tail" version="1.1" viewBox="0 0 14.597 14.58" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="translate(-173.71 -87.184)">
|
||||
<path d="m188.19 87.657c-1.469 2.3218-3.9315 3.8312-6.667 4.0865-2.2309-1.7379-4.9781-2.6816-7.8061-2.6815h-5.1e-4v12.702h12.702v-5.1e-4c2e-5 -1.9998-0.47213-3.9713-1.378-5.754 2.0709-1.6834 3.2732-4.2102 3.273-6.8791-6e-5 -0.49375-0.0413-0.98662-0.1235-1.4735z" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round" stroke-width=".33225" style="paint-order:stroke fill markers"/>
|
||||
</g>
|
||||
</svg>
|
||||
<div :class="$style.content">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
withDefaults(defineProps<{
|
||||
tail?: 'left' | 'right' | 'none';
|
||||
negativeMargin?: boolean;
|
||||
shadow?: boolean;
|
||||
}>(), {
|
||||
tail: 'right',
|
||||
negativeMargin: false,
|
||||
shadow: false,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style module lang="scss">
|
||||
.root {
|
||||
--fukidashi-radius: var(--radius);
|
||||
--fukidashi-bg: var(--panel);
|
||||
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
min-height: calc(var(--fukidashi-radius) * 2);
|
||||
padding-top: calc(var(--fukidashi-radius) * .13);
|
||||
|
||||
&.shadow {
|
||||
filter: drop-shadow(0 4px 32px var(--shadow));
|
||||
}
|
||||
|
||||
&.left {
|
||||
padding-left: calc(var(--fukidashi-radius) * .13);
|
||||
|
||||
&.negativeMergin {
|
||||
margin-left: calc(calc(var(--fukidashi-radius) * .13) * -1);
|
||||
}
|
||||
}
|
||||
|
||||
&.right {
|
||||
padding-right: calc(var(--fukidashi-radius) * .13);
|
||||
|
||||
&.negativeMergin {
|
||||
margin-right: calc(calc(var(--fukidashi-radius) * .13) * -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--fukidashi-bg);
|
||||
border-radius: var(--fukidashi-radius);
|
||||
}
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
.tail {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
display: block;
|
||||
width: calc(var(--fukidashi-radius) * 1.13);
|
||||
height: auto;
|
||||
fill: var(--fukidashi-bg);
|
||||
}
|
||||
|
||||
.left .tail {
|
||||
left: 0;
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
|
||||
.right .tail {
|
||||
right: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<template>
|
||||
<MkA v-user-preview="canonical" :class="[$style.root, { [$style.isMe]: isMe }]" :to="url" :style="{ background: bgCss }" :behavior="navigationBehavior">
|
||||
<MkA v-user-preview="canonical" :class="[$style.root, { [$style.isMe]: isMe }]" :to="url" :behavior="navigationBehavior">
|
||||
<img :class="$style.icon" :src="avatarUrl" alt="">
|
||||
<span>
|
||||
<span>@{{ username }}</span>
|
||||
@@ -16,7 +16,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<script lang="ts" setup>
|
||||
import { toUnicode } from 'punycode';
|
||||
import { computed } from 'vue';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import { host as localHost } from '@@/js/config.js';
|
||||
import { $i } from '@/account.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
@@ -37,11 +36,7 @@ const isMe = $i && (
|
||||
`@${props.username}@${toUnicode(props.host)}` === `@${$i.username}@${toUnicode(localHost)}`.toLowerCase()
|
||||
);
|
||||
|
||||
const bg = tinycolor(getComputedStyle(document.documentElement).getPropertyValue(isMe ? '--mentionMe' : '--mention'));
|
||||
bg.setAlpha(0.1);
|
||||
const bgCss = bg.toRgbString();
|
||||
|
||||
const avatarUrl = computed(() => defaultStore.state.disableShowingAnimatedImages
|
||||
const avatarUrl = computed(() => defaultStore.state.disableShowingAnimatedImages || defaultStore.state.dataSaver.avatar
|
||||
? getStaticImageUrl(`/avatar/@${props.username}@${props.host}`)
|
||||
: `/avatar/@${props.username}@${props.host}`,
|
||||
);
|
||||
@@ -53,9 +48,11 @@ const avatarUrl = computed(() => defaultStore.state.disableShowingAnimatedImages
|
||||
padding: 4px 8px 4px 4px;
|
||||
border-radius: 999px;
|
||||
color: var(--mention);
|
||||
background: color(from var(--mention) srgb r g b / 0.1);
|
||||
|
||||
&.isMe {
|
||||
color: var(--mentionMe);
|
||||
background: color(from var(--mentionMe) srgb r g b / 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<MkInstanceTicker v-if="showTicker" :instance="appearNote.user.instance"/>
|
||||
<div style="container-type: inline-size;">
|
||||
<p v-if="appearNote.cw != null" :class="$style.cw">
|
||||
<Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :author="appearNote.user" :nyaize="'respect'"/>
|
||||
<Mfm
|
||||
v-if="appearNote.cw != ''"
|
||||
:text="appearNote.cw"
|
||||
:author="appearNote.user"
|
||||
:nyaize="'respect'"
|
||||
:enableEmojiMenu="true"
|
||||
:enableEmojiMenuReaction="true"
|
||||
/>
|
||||
<MkCwButton v-model="showContent" :text="appearNote.text" :renote="appearNote.renote" :files="appearNote.files" :poll="appearNote.poll" style="margin: 4px 0;"/>
|
||||
</p>
|
||||
<div v-show="appearNote.cw == null || showContent" :class="[{ [$style.contentCollapsed]: collapsed }]">
|
||||
|
||||
@@ -68,7 +68,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</header>
|
||||
<div :class="$style.noteContent">
|
||||
<p v-if="appearNote.cw != null" :class="$style.cw">
|
||||
<Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :author="appearNote.user" :nyaize="'respect'"/>
|
||||
<Mfm
|
||||
v-if="appearNote.cw != ''"
|
||||
:text="appearNote.cw"
|
||||
:author="appearNote.user"
|
||||
:nyaize="'respect'"
|
||||
:enableEmojiMenu="true"
|
||||
:enableEmojiMenuReaction="true"
|
||||
/>
|
||||
<MkCwButton v-model="showContent" :text="appearNote.text" :renote="appearNote.renote" :files="appearNote.files" :poll="appearNote.poll"/>
|
||||
</p>
|
||||
<div v-show="appearNote.cw == null || showContent">
|
||||
|
||||
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
<template>
|
||||
<header :class="$style.root">
|
||||
<component :is="defaultStore.state.enableCondensedLine ? 'MkCondensedLine' : 'div'" :minScale="0" style="min-width: 0;">
|
||||
<component :is="defaultStore.state.enableCondensedLine ? 'MkCondensedLine' : 'div'" :minScale="0.7" style="min-width: 0;">
|
||||
<div style="display: flex; white-space: nowrap; align-items: baseline;">
|
||||
<div v-if="mock" :class="$style.name">
|
||||
<MkUserName :user="note.user"/>
|
||||
|
||||
@@ -7,13 +7,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<div :class="$style.root">
|
||||
<div :class="$style.head">
|
||||
<MkAvatar v-if="['pollEnded', 'note'].includes(notification.type) && 'note' in notification" :class="$style.icon" :user="notification.note.user" link preview/>
|
||||
<MkAvatar v-else-if="['roleAssigned', 'achievementEarned'].includes(notification.type)" :class="$style.icon" :user="$i" link preview/>
|
||||
<MkAvatar v-else-if="['roleAssigned', 'achievementEarned', 'exportCompleted', 'login'].includes(notification.type)" :class="$style.icon" :user="$i" link preview/>
|
||||
<div v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'" :class="[$style.icon, $style.icon_reactionGroupHeart]"><i class="ti ti-heart" style="line-height: 1;"></i></div>
|
||||
<div v-else-if="notification.type === 'reaction:grouped'" :class="[$style.icon, $style.icon_reactionGroup]"><i class="ti ti-plus" style="line-height: 1;"></i></div>
|
||||
<div v-else-if="notification.type === 'renote:grouped'" :class="[$style.icon, $style.icon_renoteGroup]"><i class="ti ti-repeat" style="line-height: 1;"></i></div>
|
||||
<img v-else-if="notification.type === 'test'" :class="$style.icon" :src="infoImageUrl"/>
|
||||
<MkAvatar v-else-if="'user' in notification" :class="$style.icon" :user="notification.user" link preview/>
|
||||
<MkAvatar v-else-if="notification.type === 'exportCompleted'" :class="$style.icon" :user="$i" link preview/>
|
||||
<img v-else-if="'icon' in notification && notification.icon != null" :class="[$style.icon, $style.icon_app]" :src="notification.icon" alt=""/>
|
||||
<div
|
||||
:class="[$style.subIcon, {
|
||||
@@ -27,6 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
[$style.t_pollEnded]: notification.type === 'pollEnded',
|
||||
[$style.t_achievementEarned]: notification.type === 'achievementEarned',
|
||||
[$style.t_exportCompleted]: notification.type === 'exportCompleted',
|
||||
[$style.t_login]: notification.type === 'login',
|
||||
[$style.t_roleAssigned]: notification.type === 'roleAssigned' && notification.role.iconUrl == null,
|
||||
}]"
|
||||
>
|
||||
@@ -40,6 +40,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<i v-else-if="notification.type === 'pollEnded'" class="ti ti-chart-arrows"></i>
|
||||
<i v-else-if="notification.type === 'achievementEarned'" class="ti ti-medal"></i>
|
||||
<i v-else-if="notification.type === 'exportCompleted'" class="ti ti-archive"></i>
|
||||
<i v-else-if="notification.type === 'login'" class="ti ti-login-2"></i>
|
||||
<template v-else-if="notification.type === 'roleAssigned'">
|
||||
<img v-if="notification.role.iconUrl" style="height: 1.3em; vertical-align: -22%;" :src="notification.role.iconUrl" alt=""/>
|
||||
<i v-else class="ti ti-badges"></i>
|
||||
@@ -59,6 +60,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<span v-else-if="notification.type === 'note'">{{ i18n.ts._notification.newNote }}: <MkUserName :user="notification.note.user"/></span>
|
||||
<span v-else-if="notification.type === 'roleAssigned'">{{ i18n.ts._notification.roleAssigned }}</span>
|
||||
<span v-else-if="notification.type === 'achievementEarned'">{{ i18n.ts._notification.achievementEarned }}</span>
|
||||
<span v-else-if="notification.type === 'login'">{{ i18n.ts._notification.login }}</span>
|
||||
<span v-else-if="notification.type === 'test'">{{ i18n.ts._notification.testNotification }}</span>
|
||||
<span v-else-if="notification.type === 'exportCompleted'">{{ i18n.tsx._notification.exportOfXCompleted({ x: exportEntityName[notification.exportedEntity] }) }}</span>
|
||||
<MkA v-else-if="notification.type === 'follow' || notification.type === 'mention' || notification.type === 'reply' || notification.type === 'renote' || notification.type === 'quote' || notification.type === 'reaction' || notification.type === 'receiveFollowRequest' || notification.type === 'followRequestAccepted'" v-user-preview="notification.user.id" :class="$style.headerName" :to="userPage(notification.user)"><MkUserName :user="notification.user"/></MkA>
|
||||
@@ -225,6 +227,7 @@ function getActualReactedUsersCount(notification: Misskey.entities.Notification)
|
||||
--eventReactionHeart: var(--love);
|
||||
--eventReaction: #e99a0b;
|
||||
--eventAchievement: #cb9a11;
|
||||
--eventLogin: #007aff;
|
||||
--eventOther: #88a6b7;
|
||||
}
|
||||
|
||||
@@ -346,6 +349,12 @@ function getActualReactedUsersCount(notification: Misskey.entities.Notification)
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.t_login {
|
||||
padding: 3px;
|
||||
background: var(--eventLogin);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.tail {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
@@ -7,7 +7,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<div v-show="props.modelValue.length != 0" :class="$style.root">
|
||||
<Sortable :modelValue="props.modelValue" :class="$style.files" itemKey="id" :animation="150" :delay="100" :delayOnTouchOnly="true" @update:modelValue="v => emit('update:modelValue', v)">
|
||||
<template #item="{element}">
|
||||
<div :class="$style.file" @click="showFileMenu(element, $event)" @contextmenu.prevent="showFileMenu(element, $event)">
|
||||
<div
|
||||
:class="$style.file"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@click="showFileMenu(element, $event)"
|
||||
@keydown.space.enter="showFileMenu(element, $event)"
|
||||
@contextmenu.prevent="showFileMenu(element, $event)"
|
||||
>
|
||||
<MkDriveFileThumbnail :data-id="element.id" :class="$style.thumbnail" :file="element" fit="cover"/>
|
||||
<div v-if="element.isSensitive" :class="$style.sensitive">
|
||||
<i class="ti ti-eye-exclamation" style="margin: auto;"></i>
|
||||
@@ -133,7 +140,7 @@ async function crop(file: Misskey.entities.DriveFile): Promise<void> {
|
||||
emit('replaceFile', file, newFile);
|
||||
}
|
||||
|
||||
function showFileMenu(file: Misskey.entities.DriveFile, ev: MouseEvent): void {
|
||||
function showFileMenu(file: Misskey.entities.DriveFile, ev: MouseEvent | KeyboardEvent): void {
|
||||
if (menuShowing) return;
|
||||
|
||||
const isImage = file.type.startsWith('image/');
|
||||
@@ -199,6 +206,10 @@ function showFileMenu(file: Misskey.entities.DriveFile, ev: MouseEvent): void {
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
cursor: move;
|
||||
|
||||
&:focus-visible {
|
||||
outline-offset: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.thumbnail {
|
||||
|
||||
@@ -32,7 +32,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<template #prefix><i class="ti ti-lock"></i></template>
|
||||
<template #caption><button class="_textButton" type="button" @click="resetPassword">{{ i18n.ts.forgotPassword }}</button></template>
|
||||
</MkInput>
|
||||
<MkButton type="submit" large primary rounded :disabled="signing" style="margin: 0 auto;">{{ signing ? i18n.ts.loggingIn : i18n.ts.login }}</MkButton>
|
||||
<MkCaptcha v-if="instance.enableHcaptcha" ref="hcaptcha" v-model="hCaptchaResponse" :class="$style.captcha" provider="hcaptcha" :sitekey="instance.hcaptchaSiteKey"/>
|
||||
<MkCaptcha v-if="instance.enableMcaptcha" ref="mcaptcha" v-model="mCaptchaResponse" :class="$style.captcha" provider="mcaptcha" :sitekey="instance.mcaptchaSiteKey" :instanceUrl="instance.mcaptchaInstanceUrl"/>
|
||||
<MkCaptcha v-if="instance.enableRecaptcha" ref="recaptcha" v-model="reCaptchaResponse" :class="$style.captcha" provider="recaptcha" :sitekey="instance.recaptchaSiteKey"/>
|
||||
<MkCaptcha v-if="instance.enableTurnstile" ref="turnstile" v-model="turnstileResponse" :class="$style.captcha" provider="turnstile" :sitekey="instance.turnstileSiteKey"/>
|
||||
<MkButton type="submit" large primary rounded :disabled="captchaFailed || signing" style="margin: 0 auto;">{{ signing ? i18n.ts.loggingIn : i18n.ts.login }}</MkButton>
|
||||
</div>
|
||||
<div v-if="totpLogin" class="2fa-signin" :class="{ securityKeys: user && user.securityKeys }">
|
||||
<div v-if="user && user.securityKeys" class="twofa-group tap-group">
|
||||
@@ -68,7 +72,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, ref } from 'vue';
|
||||
import { computed, defineAsyncComponent, ref } from 'vue';
|
||||
import { toUnicode } from 'punycode/';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { supported as webAuthnSupported, get as webAuthnRequest, parseRequestOptionsFromJSON } from '@github/webauthn-json/browser-ponyfill';
|
||||
@@ -85,6 +89,8 @@ import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||
import { login } from '@/account.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { instance } from '@/instance.js';
|
||||
import MkCaptcha, { type Captcha } from '@/components/MkCaptcha.vue';
|
||||
|
||||
const signing = ref(false);
|
||||
const user = ref<Misskey.entities.UserDetailed | null>(null);
|
||||
@@ -98,6 +104,22 @@ const isBackupCode = ref(false);
|
||||
const queryingKey = ref(false);
|
||||
let credentialRequest: CredentialRequestOptions | null = null;
|
||||
const passkey_context = ref('');
|
||||
const hcaptcha = ref<Captcha | undefined>();
|
||||
const mcaptcha = ref<Captcha | undefined>();
|
||||
const recaptcha = ref<Captcha | undefined>();
|
||||
const turnstile = ref<Captcha | undefined>();
|
||||
const hCaptchaResponse = ref<string | null>(null);
|
||||
const mCaptchaResponse = ref<string | null>(null);
|
||||
const reCaptchaResponse = ref<string | null>(null);
|
||||
const turnstileResponse = ref<string | null>(null);
|
||||
|
||||
const captchaFailed = computed((): boolean => {
|
||||
return (
|
||||
instance.enableHcaptcha && !hCaptchaResponse.value ||
|
||||
instance.enableMcaptcha && !mCaptchaResponse.value ||
|
||||
instance.enableRecaptcha && !reCaptchaResponse.value ||
|
||||
instance.enableTurnstile && !turnstileResponse.value);
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(ev: 'login', v: any): void;
|
||||
@@ -227,6 +249,10 @@ function onSubmit(): void {
|
||||
misskeyApi('signin', {
|
||||
username: username.value,
|
||||
password: password.value,
|
||||
'hcaptcha-response': hCaptchaResponse.value,
|
||||
'm-captcha-response': mCaptchaResponse.value,
|
||||
'g-recaptcha-response': reCaptchaResponse.value,
|
||||
'turnstile-response': turnstileResponse.value,
|
||||
token: user.value?.twoFactorEnabled ? token.value : undefined,
|
||||
}).then(res => {
|
||||
emit('login', res);
|
||||
@@ -236,6 +262,11 @@ function onSubmit(): void {
|
||||
}
|
||||
|
||||
function loginFailed(err: any): void {
|
||||
hcaptcha.value?.reset?.();
|
||||
mcaptcha.value?.reset?.();
|
||||
recaptcha.value?.reset?.();
|
||||
turnstile.value?.reset?.();
|
||||
|
||||
switch (err.id) {
|
||||
case '6cc579cc-885d-43d8-95c2-b8c7fc963280': {
|
||||
os.alert({
|
||||
|
||||
@@ -81,10 +81,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
import { ref, computed } from 'vue';
|
||||
import { toUnicode } from 'punycode/';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import * as config from '@@/js/config.js';
|
||||
import MkButton from './MkButton.vue';
|
||||
import MkInput from './MkInput.vue';
|
||||
import MkCaptcha, { type Captcha } from '@/components/MkCaptcha.vue';
|
||||
import * as config from '@@/js/config.js';
|
||||
import * as os from '@/os.js';
|
||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||
import { login } from '@/account.js';
|
||||
@@ -105,6 +105,7 @@ const emit = defineEmits<{
|
||||
const host = toUnicode(config.host);
|
||||
|
||||
const hcaptcha = ref<Captcha | undefined>();
|
||||
const mcaptcha = ref<Captcha | undefined>();
|
||||
const recaptcha = ref<Captcha | undefined>();
|
||||
const turnstile = ref<Captcha | undefined>();
|
||||
|
||||
@@ -281,6 +282,7 @@ async function onSubmit(): Promise<void> {
|
||||
} catch {
|
||||
submitting.value = false;
|
||||
hcaptcha.value?.reset?.();
|
||||
mcaptcha.value?.reset?.();
|
||||
recaptcha.value?.reset?.();
|
||||
turnstile.value?.reset?.();
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
<template>
|
||||
<span :class="$style.container">
|
||||
<span ref="content" :class="$style.content">
|
||||
<span ref="content" :class="$style.content" :style="{ maxWidth: `${100 / minScale}%` }">
|
||||
<slot/>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
@@ -48,9 +48,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="user.followedMessage != null" class="followedMessage">
|
||||
<div style="border: solid 1px var(--love); border-radius: 6px; background: color-mix(in srgb, var(--love), transparent 90%); padding: 6px 8px;">
|
||||
<Mfm :text="user.followedMessage" :author="user"/>
|
||||
</div>
|
||||
<MkFukidashi class="fukidashi" :tail="narrow ? 'none' : 'left'" negativeMargin shadow>
|
||||
<div class="messageHeader">{{ i18n.ts.messageToFollower }}</div>
|
||||
<div><Mfm :text="user.followedMessage" :author="user"/></div>
|
||||
</MkFukidashi>
|
||||
</div>
|
||||
<div v-if="user.roles.length > 0" class="roles">
|
||||
<span v-for="role in user.roles" :key="role.id" v-tooltip="role.description" class="role" :style="{ '--color': role.color }">
|
||||
@@ -161,6 +162,7 @@ import * as Misskey from 'misskey-js';
|
||||
import MkNote from '@/components/MkNote.vue';
|
||||
import MkFollowButton from '@/components/MkFollowButton.vue';
|
||||
import MkAccountMoved from '@/components/MkAccountMoved.vue';
|
||||
import MkFukidashi from '@/components/MkFukidashi.vue';
|
||||
import MkRemoteCaution from '@/components/MkRemoteCaution.vue';
|
||||
import MkTextarea from '@/components/MkTextarea.vue';
|
||||
import MkOmit from '@/components/MkOmit.vue';
|
||||
@@ -467,7 +469,18 @@ onUnmounted(() => {
|
||||
|
||||
> .followedMessage {
|
||||
padding: 24px 24px 0 154px;
|
||||
font-size: 0.9em;
|
||||
|
||||
> .fukidashi {
|
||||
display: block;
|
||||
--fukidashi-bg: color-mix(in srgb, var(--love), var(--panel) 85%);
|
||||
--fukidashi-radius: 16px;
|
||||
font-size: 0.9em;
|
||||
|
||||
.messageHeader {
|
||||
opacity: 0.7;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .roles {
|
||||
|
||||
@@ -109,6 +109,11 @@ export function getConfig(): UserConfig {
|
||||
}
|
||||
},
|
||||
},
|
||||
preprocessorOptions: {
|
||||
scss: {
|
||||
api: 'modern-compiler',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
define: {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"type": "module",
|
||||
"name": "misskey-js",
|
||||
"version": "2024.9.0-alpha.12",
|
||||
"version": "2024.10.0-alpha.0",
|
||||
"description": "Misskey SDK for JavaScript",
|
||||
"license": "MIT",
|
||||
"main": "./built/index.js",
|
||||
|
||||
@@ -4288,7 +4288,14 @@ export type components = {
|
||||
exportedEntity: 'antenna' | 'blocking' | 'clip' | 'customEmoji' | 'favorite' | 'following' | 'muting' | 'note' | 'userList';
|
||||
/** Format: id */
|
||||
fileId: string;
|
||||
}) | ({
|
||||
}) | {
|
||||
/** Format: id */
|
||||
id: string;
|
||||
/** Format: date-time */
|
||||
createdAt: string;
|
||||
/** @enum {string} */
|
||||
type: 'login';
|
||||
} | ({
|
||||
/** Format: id */
|
||||
id: string;
|
||||
/** Format: date-time */
|
||||
@@ -5177,6 +5184,8 @@ export type operations = {
|
||||
urlPreviewRequireContentLength: boolean;
|
||||
urlPreviewUserAgent: string | null;
|
||||
urlPreviewSummaryProxyUrl: string | null;
|
||||
federation: string;
|
||||
federationHosts: string[];
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -9428,6 +9437,9 @@ export type operations = {
|
||||
urlPreviewRequireContentLength?: boolean;
|
||||
urlPreviewUserAgent?: string | null;
|
||||
urlPreviewSummaryProxyUrl?: string | null;
|
||||
/** @enum {string} */
|
||||
federation?: 'all' | 'none' | 'specified';
|
||||
federationHosts?: string[];
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -18545,8 +18557,8 @@ export type operations = {
|
||||
untilId?: string;
|
||||
/** @default true */
|
||||
markAsRead?: boolean;
|
||||
includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
||||
excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
||||
includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'login' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
||||
excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'login' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -18613,8 +18625,8 @@ export type operations = {
|
||||
untilId?: string;
|
||||
/** @default true */
|
||||
markAsRead?: boolean;
|
||||
includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'app' | 'test' | 'reaction:grouped' | 'renote:grouped' | 'pollVote' | 'groupInvited')[];
|
||||
excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'app' | 'test' | 'reaction:grouped' | 'renote:grouped' | 'pollVote' | 'groupInvited')[];
|
||||
includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'login' | 'app' | 'test' | 'reaction:grouped' | 'renote:grouped' | 'pollVote' | 'groupInvited')[];
|
||||
excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'achievementEarned' | 'exportCompleted' | 'login' | 'app' | 'test' | 'reaction:grouped' | 'renote:grouped' | 'pollVote' | 'groupInvited')[];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -210,6 +210,12 @@ async function composeNotification(data: PushNotificationDataMap[keyof PushNotif
|
||||
tag: `achievement:${data.body.achievement}`,
|
||||
}];
|
||||
|
||||
case 'login':
|
||||
return [i18n.ts._notification.login, {
|
||||
badge: iconUrl('login-2'),
|
||||
data,
|
||||
}];
|
||||
|
||||
case 'exportCompleted': {
|
||||
const entityName = {
|
||||
antenna: i18n.ts.antennas,
|
||||
|
||||
@@ -50,4 +50,5 @@ export type BadgeNames =
|
||||
| 'quote'
|
||||
| 'repeat'
|
||||
| 'user-plus'
|
||||
| 'users';
|
||||
| 'users'
|
||||
| 'login-2';
|
||||
|
||||
793
pnpm-lock.yaml
generated
793
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user