diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2022-07-13 21:59:47 +0900 |
|---|---|---|
| committer | syuilo <Syuilotan@yahoo.co.jp> | 2022-07-13 21:59:47 +0900 |
| commit | bce48dfee933d9feb3be381ad22ea765dd6a3aab (patch) | |
| tree | b21a3a765040469885d286487245aeaed373bba6 | |
| parent | Merge branch 'develop' (diff) | |
| parent | 12.113.0 (diff) | |
| download | misskey-bce48dfee933d9feb3be381ad22ea765dd6a3aab.tar.gz misskey-bce48dfee933d9feb3be381ad22ea765dd6a3aab.tar.bz2 misskey-bce48dfee933d9feb3be381ad22ea765dd6a3aab.zip | |
Merge branch 'develop'
91 files changed, 1154 insertions, 826 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 37e3d52a0e..91d4edf120 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,15 @@ You should also include the user name that made the change. --> +## 12.113.0 (2022/07/13) + +### Improvements +- Support <plain> syntax for MFM + +### Bugfixes +- Server: Fix crash at startup if TensorFlow is not supported @mei23 +- Client: URLエンコードされたルーティングを修正 + ## 12.112.3 (2022/07/09) ### Improvements diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml index 0d49d2292b..1289fba44d 100644 --- a/locales/ar-SA.yml +++ b/locales/ar-SA.yml @@ -804,6 +804,10 @@ oneDay: "يوم" oneWeek: "أسبوع" failedToFetchAccountInformation: "تعذر جلب معلومات الحساب" file: "الملفات" +reverse: "اقلب" +colored: "ملوّن" +label: "التسمية" +localOnly: "المحلي فقط" _emailUnavailable: used: "هذا البريد الإلكتروني مستخدم" format: "صيغة البريد الإلكتروني غير صالحة" diff --git a/locales/bn-BD.yml b/locales/bn-BD.yml index 3c449591d2..6017566bb0 100644 --- a/locales/bn-BD.yml +++ b/locales/bn-BD.yml @@ -844,6 +844,10 @@ reflectMayTakeTime: "এটির কাজ দেখা যেতে কিছ failedToFetchAccountInformation: "অ্যাকাউন্টের তথ্য উদ্ধার করা যায়নি" rateLimitExceeded: "রেট লিমিট ছাড়িয়ে গেছে " file: "ফাইলগুলি" +reverse: "উল্টান" +colored: "রঙ্গিন" +label: "লেবেল" +localOnly: "শুধুমাত্র লোকাল" _emailUnavailable: used: "এই ইমেইল ঠিকানাটি ইতোমধ্যে ব্যবহৃত হয়েছে" format: "এই ইমেল ঠিকানাটি সঠিকভাবে লিখা হয়নি" diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml index d6d83fefad..1c859b68f5 100644 --- a/locales/ca-ES.yml +++ b/locales/ca-ES.yml @@ -111,6 +111,14 @@ reactionSettingDescription2: "Arrossega per reordenar, fes clic per suprimir, pr rememberNoteVisibility: "Recorda la configuració de visibilitat de les notes" attachCancel: "Eliminar el fitxer adjunt" markAsSensitive: "Marcar com a NSFW" +unmarkAsSensitive: "Deixar de marcar com a sensible" +enterFileName: "Defineix nom del fitxer" +mute: "Silencia" +unmute: "Deixa de silenciar" +block: "Bloqueja" +unblock: "Desbloqueja" +suspend: "Suspèn" +unsuspend: "Deixa de suspendre" instances: "Instàncies" remove: "Eliminar" nsfw: "NSFW" @@ -148,6 +156,8 @@ _profile: username: "Nom d'usuari" _exportOrImport: followingList: "Seguint" + muteList: "Silencia" + blockingList: "Bloqueja" userLists: "Llistes" _pages: script: diff --git a/locales/de-DE.yml b/locales/de-DE.yml index 39c0f09a9c..dfa65198be 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -869,6 +869,32 @@ logoutConfirm: "Wirklich abmelden?" lastActiveDate: "Zuletzt verwendet am" statusbar: "Statusleiste" pleaseSelect: "Wähle eine Option" +reverse: "Umkehren" +colored: "Farbig" +refreshInterval: "Aktualisierungsrate" +label: "Beschriftung" +type: "Art" +speed: "Geschwindigkeit" +slow: "Langsam" +fast: "Schnell" +sensitiveMediaDetection: "Erkennung von NSFW-Medien" +localOnly: "Nur Lokal" +remoteOnly: "Nur für fremde Instanzen" +failedToUpload: "Hochladen fehlgeschlagen" +cannotUploadBecauseInappropriate: "Diese Datei kann nicht hochgeladen werden, da Anteile der Datei als möglicherweise NSFW festgestellt wurden." +cannotUploadBecauseNoFreeSpace: "Die Datei konnte nicht hochgeladen werden, da dein Drive-Speicherplatz aufgebraucht ist." +beta: "Beta" +enableAutoSensitive: "NSFW-Automarkierung" +enableAutoSensitiveDescription: "Setzt soweit möglich durch Verwendung von Machine Learning automatisch NSFW-Markierungen für Medien, die NSFW-Anteile beinhalten. Auch wenn du diese Option deaktiviert hast, ist sie möglicherweise auf Instanzebene aktiviert." +activeEmailValidationDescription: "Aktivert strengere Überprüfung von E-Mail-Adressen, d.h. Testen auf Wegwerfadressen und darauf, ob mit der Adresse tatsächlich kommuniziert werden kann. Ist dies deaktiviert, so wird nur das Format der E-Mail überprüft." +_sensitiveMediaDetection: + description: "Ermöglicht eine Erleichterung der Servermoderation durch die automatische Erkennungen von NSFW-Medien unter Verwendung von Machine Learning. Hierdurch wird die Serverlast etwas erhöht." + sensitivity: "Erkennungssensitivität" + sensitivityDescription: "Durch das Senken der Sensitivität kann die Anzahl an Fehlerkennungen (sog. false positives) reduziert werden. Durch ein Erhöhen dieser kann die Anzahl an verpassten Erkennungen (sog. false negatives) reduziert werden." + setSensitiveFlagAutomatically: "Als NSFW markieren" + setSensitiveFlagAutomaticallyDescription: "Die Resultate der internen Erkennung werden beibehalten, auch wenn diese Option deaktiviert ist." + analyzeVideos: "Videoanalyse aktivieren" + analyzeVideosDescription: "Analysiert zusätzlich zu Bildern auch Videos. Die Last des Servers wird hierdurch etwas erhöht." _emailUnavailable: used: "Diese Email-Adresse wird bereits verwendet" format: "Das Format dieser Email-Adresse ist ungültig" diff --git a/locales/en-US.yml b/locales/en-US.yml index 363209e166..f0a9924cd7 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -869,6 +869,32 @@ logoutConfirm: "Really log out?" lastActiveDate: "Last used at" statusbar: "Status bar" pleaseSelect: "Select an option" +reverse: "Reverse" +colored: "Colored" +refreshInterval: "Update interval " +label: "Label" +type: "Type" +speed: "Speed" +slow: "Slow" +fast: "Fast" +sensitiveMediaDetection: "Detection of NSFW media" +localOnly: "Local only" +remoteOnly: "Remote only" +failedToUpload: "Upload failed" +cannotUploadBecauseInappropriate: "This file could not be uploaded because parts of it have been detected as potentially NSFW." +cannotUploadBecauseNoFreeSpace: "Upload failed due to lack of Drive capacity." +beta: "Beta" +enableAutoSensitive: "Automatic NSFW-Marking" +enableAutoSensitiveDescription: "Allows automatic detection and marking of NSFW media through Machine Learning where possible. Even if this option is disabled, it may be enabled instance-wide." +activeEmailValidationDescription: "Enables stricter validation of email addresses, which includes checking for disposable addresses and by whether it can actually be communicated with. When unchecked, only the format of the email is validated." +_sensitiveMediaDetection: + description: "Reduces the effort of server moderation through automatically recognizing NSFW media via Machine Learning. This will slightly increase the load on the server." + sensitivity: "Detection sensitivity" + sensitivityDescription: "Reducing the sensitivity will lead to fewer misdetections (false positives) whereas increasing it will lead to fewer missed detections (false negatives)." + setSensitiveFlagAutomatically: "Mark as NSFW" + setSensitiveFlagAutomaticallyDescription: "The results of the internal detection will be retained even if this option is turned off." + analyzeVideos: "Enable analysis of videos" + analyzeVideosDescription: "Analyzes videos in addition to images. This will slightly increase the load on the server." _emailUnavailable: used: "This email address is already being used" format: "The format of this email address is invalid" diff --git a/locales/es-ES.yml b/locales/es-ES.yml index 13dd3f67b7..a8f6aaa79d 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -861,6 +861,10 @@ document: "Documento" numberOfPageCache: "Cantidad de páginas cacheadas" numberOfPageCacheDescription: "Al aumentar el número mejora la conveniencia pero tambien puede aumentar la carga y la memoria a usarse" logoutConfirm: "¿Cerrar sesión?" +reverse: "Echar de un capirotazo" +colored: "Color" +label: "Etiqueta" +localOnly: "Solo local" _emailUnavailable: used: "Ya fue usado" format: "Formato no válido." diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml index ebc6d16a39..c5f803bb88 100644 --- a/locales/fr-FR.yml +++ b/locales/fr-FR.yml @@ -839,6 +839,10 @@ rateLimitExceeded: "Limite de taux dépassée" cropImage: "Recadrer l'image" cropImageAsk: "Voulez-vous recadrer cette image ?" file: "Fichiers" +reverse: "Inverser" +colored: "Coloré" +label: "Étiquette" +localOnly: "Local seulement" _emailUnavailable: used: "Non disponible" format: "Le format de cette adresse de courriel est invalide" diff --git a/locales/id-ID.yml b/locales/id-ID.yml index 585b029004..d543fae862 100644 --- a/locales/id-ID.yml +++ b/locales/id-ID.yml @@ -848,6 +848,10 @@ rateLimitExceeded: "Batas sudah terlampaui" cropImage: "potong gambar" cropImageAsk: "Ingin memotong gambar?" file: "Berkas" +reverse: "Balik" +colored: "Diwarnai" +label: "Label" +localOnly: "Hanya lokal" _emailUnavailable: used: "Alamat surel ini telah digunakan" format: "Format tidak valid." diff --git a/locales/it-IT.yml b/locales/it-IT.yml index 0f20544193..eb7478dd51 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -810,6 +810,10 @@ oneHour: "1 ora" oneDay: "1 giorno" oneWeek: "1 settimana" file: "Allegati" +reverse: "Inverti" +colored: "Colorato" +label: "Etichetta" +localOnly: "Soltanto locale" _emailUnavailable: used: "Email già in uso" format: "Formato email non valido" diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml index 156918fe21..bae0ab5e1f 100644 --- a/locales/ja-KS.yml +++ b/locales/ja-KS.yml @@ -658,6 +658,7 @@ hide: "隠す" searchByGoogle: "探す" indefinitely: "無期限" file: "ファイル" +colored: "色付き" _ad: back: "戻る" _gallery: diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 8ceceaa509..781de61062 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -203,6 +203,7 @@ done: "완료" processing: "처리중" preview: "미리보기" default: "기본값" +defaultValueIs: "기본값: {value}" noCustomEmojis: "이모지가 없습니다" noJobs: "작업이 없습니다" federating: "연합 중" @@ -381,6 +382,7 @@ administrator: "관리자" token: "토큰" twoStepAuthentication: "2단계 인증" moderator: "모더레이터" +moderation: "모더레이션" nUsersMentioned: "{n}명이 언급함" securityKey: "보안 키" securityKeyName: "키 이름" @@ -854,9 +856,44 @@ noEmailServerWarning: "메일 서버가 설정되어 있지 않습니다." thereIsUnresolvedAbuseReportWarning: "해결되지 않은 신고가 있습니다." recommended: "추천" check: "체크" +driveCapOverrideLabel: "이 유저의 드라이브 용량을 변경" +driveCapOverrideCaption: "0 이하를 지정하면 해제됩니다." +requireAdminForView: "열람하려면 관리자 계정으로 로그인해야 합니다." isSystemAccount: "시스템에 의해 자동으로 생성되어 관리되는 계정입니다." typeToConfirm: "계속하시려면 {x} 을 입력하세요" deleteAccount: "계정 삭제" +document: "문서" +numberOfPageCache: "페이지 캐시 수" +numberOfPageCacheDescription: "숫자가 클 수록 편리성이 높아지지만, 시스템 자원과 메모리를 더 많이 사용합니다." +logoutConfirm: "로그아웃 하시겠습니까?" +lastActiveDate: "마지막 이용" +pleaseSelect: "선택해 주세요" +reverse: "플립" +colored: "색 입히기" +refreshInterval: "업데이트 주기" +label: "라벨" +type: "종류" +speed: "속도" +slow: "느리게" +fast: "빠르게" +sensitiveMediaDetection: "민감한 미디어 탐지" +localOnly: "로컬에만" +remoteOnly: "리모트만" +failedToUpload: "업로드 실패" +cannotUploadBecauseInappropriate: "이 파일은 부적절한 내용을 포함한다고 판단되어 업로드할 수 없습니다." +cannotUploadBecauseNoFreeSpace: "드라이브 용량이 부족하여 업로드할 수 없습니다." +beta: "베타" +enableAutoSensitive: "자동 NSFW 탐지" +enableAutoSensitiveDescription: "이용 가능할 경우 기계학습을 통해 자동으로 미디어 NSFW를 설정합니다. 이 기능을 해제하더라도, 인스턴스 정책에 따라 자동으로 설정될 수 있습니다." +activeEmailValidationDescription: "유저가 입력한 메일 주소가 일회용 메일인지, 실제로 통신할 수 있는 지 엄격하게 검사합니다. 해제할 경우 이메일 형식에 대해서만 검사합니다." +_sensitiveMediaDetection: + description: "기계학습을 통해 자동으로 민감한 미디어를 탐지하여, 모더레이션에 참고할 수 있도록 합니다. 서버의 부하를 약간 증가시킵니다." + sensitivity: "탐지 민감도" + sensitivityDescription: "민감도가 낮을수록 안전한 미디어가 잘못 탐지될 확률이 줄어들며, 높을수록 민감한 미디어가 탐지되지 않을 확률이 줄어듭니다." + setSensitiveFlagAutomatically: "자동으로 NSFW로 설정하기" + setSensitiveFlagAutomaticallyDescription: "이 설정을 해제해도 탐지 결과는 유지됩니다." + analyzeVideos: "동영상도 같이 확인하기" + analyzeVideosDescription: "사진 뿐만 아니라 동영상의 NSFW 여부도 탐지합니다. 서버의 부하를 약간 증가시킵니다." _emailUnavailable: used: "이 메일 주소는 사용중입니다" format: "형식이 올바르지 않습니다" @@ -1215,6 +1252,7 @@ _widgets: photos: "사진" digitalClock: "디지털 시계" federation: "연합" + instanceCloud: "인스턴스 구름" postForm: "글 입력란" slideshow: "슬라이드 쇼" button: "버튼" @@ -1660,6 +1698,9 @@ _deck: stackLeft: "왼쪽에 쌓기" popRight: "오른쪽으로 빼기" profile: "프로파일" + introduction: "칼럼을 조합해서 나만의 인터페이스를 구성해 보아요!" + introduction2: "나중에라도 화면 우측의 + 버튼을 눌러 새 칼럼을 추가할 수 있습니다." + widgetsIntroduction: "칼럼 메뉴의 \"위젯 편집\"에서 위젯을 추가해 주세요" _columns: main: "메인" widgets: "위젯" diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml index 9f3861756f..af7d48ea75 100644 --- a/locales/pl-PL.yml +++ b/locales/pl-PL.yml @@ -761,6 +761,9 @@ hide: "Ukryj" searchByGoogle: "Szukaj" indefinitely: "Nigdy" file: "Pliki" +reverse: "Odwróć" +colored: "Kolorowe" +label: "Etykieta" _ffVisibility: public: "Publikuj" _ad: diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml index fce11c5df2..c49cbe1388 100644 --- a/locales/ru-RU.yml +++ b/locales/ru-RU.yml @@ -203,6 +203,7 @@ done: "Готово" processing: "Обработка" preview: "Предпросмотр" default: "По умолчанию" +defaultValueIs: "По умолчанию: {value}" noCustomEmojis: "Собственные эмодзи отсутствуют" noJobs: "Нет заданий" federating: "Федерируется" @@ -834,6 +835,16 @@ instanceDefaultLightTheme: "Светлая тема по умолчанию" instanceDefaultDarkTheme: "Темная тема по умолчанию" indefinitely: "вечно" file: "Файлы" +recommended: "Рекомендуем" +check: "Проверить" +driveCapOverrideLabel: "Изменение лимита дискового пространства для этого пользователя" +reverse: "Переворот" +colored: "Выделена цветом" +label: "Метка" +localOnly: "Локально" +_sensitiveMediaDetection: + description: "Машинное обучение может быть использовано для автоматического обнаружения чувствительных медиа для модерации. Нагрузка на сервер увеличивается незначительно." + setSensitiveFlagAutomatically: "Установить флаг NSFW" _emailUnavailable: used: "Уже используется" format: "Неверный формат" diff --git a/locales/sk-SK.yml b/locales/sk-SK.yml index fc3f93248f..a5641e68f4 100644 --- a/locales/sk-SK.yml +++ b/locales/sk-SK.yml @@ -865,6 +865,32 @@ numberOfPageCacheDescription: "Zvýši rýchlosť ale tiež nároky na pamäť." logoutConfirm: "Naozaj sa chcete odhlásiť?" statusbar: "Stavový riadok" pleaseSelect: "Prosím vyberte" +reverse: "Preklopiť" +colored: "Farebné" +refreshInterval: "Interval obnovenia" +label: "Popisok" +type: "Typ" +speed: "Rýchlosť" +slow: "Pomaly" +fast: "Rýchlo" +sensitiveMediaDetection: "Detekcia citlivých médií." +localOnly: "Iba lokálne" +remoteOnly: "Len vzdialené" +failedToUpload: "Nahrávanie zlyhalo" +cannotUploadBecauseInappropriate: "Nemožno nahrať, pretože pravdepodobne obsahuje nevhodný obsah." +cannotUploadBecauseNoFreeSpace: "Nemožno nahrať kvôli nedostatku voľného úložiska." +beta: "Beta" +enableAutoSensitive: "Automatická detekcia NSFW" +enableAutoSensitiveDescription: "Ak je zapnuté, príznak NSFW sa na médiách automaticky nastaví pomocou strojového učenia. Aj keď je táto funkcia vypnutá, v niektorých prípadoch sa môže nastaviť automaticky." +activeEmailValidationDescription: "Dôkladnejšie overí e-mailovú adresu používateľa tým, že zistí, či ide o vyradenú e-mailovú adresu a či sa s ňou dá skutočne komunikovať. Ak nie je začiarknuté, e-mailová adresa sa kontroluje len ako text." +_sensitiveMediaDetection: + description: "Strojové učenie sa použije na automatickú detekciu citlivých médií na účely ich moderovania. Mierne sa zvýši zaťaženie servera." + sensitivity: "Citlivosť detekcie" + sensitivityDescription: "Nižšia citlivosť znižuje počet falošne pozitívnych výsledkov (false positives). Vyššia citlivosť znižuje počet falošne negatívnych výsledkov (false negatives)." + setSensitiveFlagAutomatically: "Nastaviť príznak NSFW" + setSensitiveFlagAutomaticallyDescription: "Aj keď je toto nastavenie vypnuté, výsledok rozhodnutia je interne uložený." + analyzeVideos: "Zapnúť analýzu videa" + analyzeVideosDescription: "Okrem obrázkov zapne detekciu aj pre videá. Zaťaženie servera sa mierne zvýši." _emailUnavailable: used: "Táto emailová adresa sa už používa" format: "Formát emailovej adresy je nesprávny" diff --git a/locales/th-TH.yml b/locales/th-TH.yml index 3e46d9667b..1170185db4 100644 --- a/locales/th-TH.yml +++ b/locales/th-TH.yml @@ -795,6 +795,31 @@ whatIsNew: "แสดงการเปลี่ยนแปลง" translate: "แปลภาษา" translatedFrom: "แปลมาจาก {x}" accountDeletionInProgress: "กำลังดำเนินการลบบัญชีอยู่" +usernameInfo: "ชื่อที่ระบุบัญชีของคุณจากผู้อื่นในเซิร์ฟเวอร์นี้ คุณสามารถใช้ตัวอักษร (a~z, A~Z), ตัวเลข (0~9) หรือขีดล่าง (_) ชื่อผู้ใช้ไม่สามารถเปลี่ยนแปลงได้ในภายหลัง" +aiChanMode: "โหมด Ai " +keepCw: "เก็บคำเตือนเนื้อหา" +pubSub: "บัญชีผับ/ย่อย" +lastCommunication: "การสื่อสารครั้งสุดท้ายล่าสุด" +resolved: "คลี่คลายแล้ว" +unresolved: "รอการเฉลย" +breakFollow: "ลบผู้ติดตาม" +itsOn: "เปิดใช้งาน" +itsOff: "ปิดใช้งาน" +emailRequiredForSignup: "จำเป็นต้องการใช้ที่อยู่อีเมลสำหรับการสมัคร" +unread: "ไม่ได้อ่าน" +filter: "กรอง" +controlPanel: "แผงควบคุม" +manageAccounts: "จัดการบัญชี" +makeReactionsPublic: "ตั้งค่าประวัติปฏิกิริยาต่อสาธารณะ" +makeReactionsPublicDescription: "การทำเช่นนี้จะทำให้รายการปฏิกิริยาที่ผ่านมาของคุณจะปรากฏต่อสาธารณะนะ" +classic: "คลาสสิค" +muteThread: "ปิดเสียงเธรด" +unmuteThread: "เปิดเสียงเธรด" +ffVisibility: "การมองเห็นผู้ติดตาม/ผู้ติดตาม" +ffVisibilityDescription: "ช่วยให้คุณสามารถกำหนดค่าได้ว่าใครสามารถดูได้ว่าคุณติดตามใครและใครติดตามคุณบ้าง" +continueThread: "ดูความต่อเนื่องเธรด" +deleteAccountConfirm: "การดำเนินการนี้จะลบบัญชีของคุณอย่างถาวรเลยนะ แน่ใจหรอดำเนินการ?" +incorrectPassword: "รหัสผ่านไม่ถูกต้อง" searchByGoogle: "ค้นหา" file: "ไฟล์" _ffVisibility: diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml index 44dd392824..7b4d77548a 100644 --- a/locales/uk-UA.yml +++ b/locales/uk-UA.yml @@ -738,6 +738,10 @@ hide: "Сховати" searchByGoogle: "Пошук" indefinitely: "Ніколи" file: "Файли" +reverse: "Перевернути" +colored: "Кольоровий" +label: "Назва" +localOnly: "Локально" _ffVisibility: public: "Опублікувати" _ad: diff --git a/locales/vi-VN.yml b/locales/vi-VN.yml index 37b961f23d..0680654879 100644 --- a/locales/vi-VN.yml +++ b/locales/vi-VN.yml @@ -869,6 +869,32 @@ logoutConfirm: "Bạn có chắc muốn đăng xuất?" lastActiveDate: "Lần cuối vào" statusbar: "Thanh trạng thái" pleaseSelect: "Chọn một lựa chọn" +reverse: "Lật" +colored: "Với màu" +refreshInterval: "Cập nhật nội bộ" +label: "Nhãn" +type: "Loại" +speed: "Tốc độ" +slow: "Chậm" +fast: "Nhanh" +sensitiveMediaDetection: "Tự động phát hiện NSFW" +localOnly: "Chỉ trên máy chủ" +remoteOnly: "Chỉ máy chủ từ xa" +failedToUpload: "Tải lên thất bại" +cannotUploadBecauseInappropriate: "Không thể tải lên tập tin này vì các phần của tập tin đã được phát hiện có khả năng là NSFW." +cannotUploadBecauseNoFreeSpace: "Tải lên không thành công do thiếu dung lượng Drive." +beta: "Beta" +enableAutoSensitive: "Tự động đánh dấu NSFW" +enableAutoSensitiveDescription: "Cho phép tự động phát hiện và đánh dấu media NSFW thông qua học máy, nếu có thể. Ngay cả khi tùy chọn này bị tắt, nó vẫn có thể được bật trên toàn máy chủ." +activeEmailValidationDescription: "Cho phép xác minh địa chỉ email chặt chẽ hơn, bao gồm việc kiểm tra các địa chỉ dùng một lần và xem nó có thực sự được giao tiếp hay không. Khi bỏ chọn, chỉ định dạng của email được xác minh." +_sensitiveMediaDetection: + description: "Giảm nỗ lực kiểm duyệt máy chủ thông qua việc tự động nhận dạng media NSFW thông qua học máy. Điều này sẽ làm tăng một chút áp lực trên máy chủ." + sensitivity: "Phát hiện nhạy cảm" + sensitivityDescription: "Giảm độ nhạy sẽ dẫn đến ít phát hiện sai hơn (dương tính giả), tăng nó sẽ dẫn đến ít phát hiện sai hơn (âm tính giả)." + setSensitiveFlagAutomatically: "Đánh dấu là NSFW" + setSensitiveFlagAutomaticallyDescription: "Kết quả của phát hiện nội bộ sẽ được giữ lại ngay cả khi tùy chọn này bị tắt." + analyzeVideos: "Bật chuẩn đoán video" + analyzeVideosDescription: "Phân tích video bên cạnh hình ảnh. Điều này sẽ làm tăng một chút áp lực trên máy chủ." _emailUnavailable: used: "Địa chỉ email đã được sử dụng" format: "Địa chỉ email không hợp lệ" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index a6b0be1051..26f745e65e 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -381,6 +381,7 @@ administrator: "管理员" token: "Token (令牌)" twoStepAuthentication: "两步验证" moderator: "监察员" +moderation: "管理" nUsersMentioned: "{n} 被提到" securityKey: "安全密钥" securityKeyName: "密钥名称" @@ -851,7 +852,40 @@ noEmailServerWarning: "电子邮件服务器未设置。" thereIsUnresolvedAbuseReportWarning: "有未解决的报告" recommended: "推荐" check: "检查" +driveCapOverrideCaption: "设定为 0 以下则会解除此限制。" +requireAdminForView: "需要使用管理员账户登录才能查看。" isSystemAccount: "该账号由系统自动创建和管理。" +typeToConfirm: "输入 {x} 以确认操作。" +deleteAccount: "删除账户" +numberOfPageCache: "缓存页数" +numberOfPageCacheDescription: "设置较高的值会更方便用户,但服务器负载和内存使用量会增加。" +logoutConfirm: "是否确认登出?" +lastActiveDate: "最后活跃时间" +statusbar: "状态栏" +pleaseSelect: "请选择" +reverse: "翻转" +colored: "彩色" +refreshInterval: "刷新间隔" +label: "标签" +speed: "速度" +slow: "慢" +fast: "快" +sensitiveMediaDetection: "检测到敏感媒体" +localOnly: "仅限本地" +remoteOnly: "仅远程" +failedToUpload: "上传失败" +cannotUploadBecauseInappropriate: "因为可能含有不适宜的内容,无法上传。" +cannotUploadBecauseNoFreeSpace: "因为已无可用空间,无法上传。" +beta: "测试" +enableAutoSensitive: "自动 NSFW 识别" +_sensitiveMediaDetection: + description: "可以使用机器学习技术自动检测敏感媒体,以便进行审核。服务器负载将略微增加。" + sensitivity: "检测敏感度" + sensitivityDescription: "敏感度较低,则误检(假阳性)会减少;敏感度较高,则漏检(假阴性)会减少。" + setSensitiveFlagAutomatically: "自动设置 NSFW 标签" + setSensitiveFlagAutomaticallyDescription: "即使关闭此配置,识别结果也会在内部保存。" + analyzeVideos: "启用对视频的检测" + analyzeVideosDescription: "除了静止图像之外,还对视频进行分析。服务器负载会略微增加。" _emailUnavailable: used: "已经被使用过" format: "无效的格式" @@ -1210,6 +1244,7 @@ _widgets: photos: "照片" digitalClock: "数字时钟" federation: "联邦宇宙" + instanceCloud: "实例云" postForm: "投稿窗口" slideshow: "幻灯片展示" button: "按钮" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index f0ed78b969..945080ee44 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -1,7 +1,7 @@ --- _lang_: "繁體中文" headlineMisskey: "貼文連繫網路" -introMisskey: "歡迎! Misskey是一個開放原始碼且去中心化的社群網路。\n透過「貼文」分享周邊新鮮事,並告訴其他人您的想法!📡\n透過「情感」功能,對大家的貼文表達情感!👍\n一起來探索這個新的世界吧!🚀" +introMisskey: "歡迎! Misskey是一個開放原始碼且去中心化的社群網路。\n透過「貼文」分享周邊新鮮事,並告訴其他人您的想法!📡\n透過「反應」功能,對大家的貼文表達情感!👍\n一起來探索這個新的世界吧!🚀" monthAndDay: "{month}月 {day}日" search: "搜尋" notifications: "通知" @@ -727,7 +727,7 @@ receiveAnnouncementFromInstance: "接收由本實例發出的電郵通知" emailNotification: "郵件通知" publish: "發佈" inChannelSearch: "頻道内搜尋" -useReactionPickerForContextMenu: "點擊右鍵開啟回應工具欄" +useReactionPickerForContextMenu: "點擊右鍵開啟反應工具欄" typingUsers: "{users}輸入中..." jumpToSpecifiedDate: "跳轉到特定日期" showingPastTimeline: "顯示過往的時間線" @@ -810,8 +810,8 @@ unread: "未讀" filter: "篩選" controlPanel: "控制台" manageAccounts: "管理帳戶" -makeReactionsPublic: "將回應設為公開" -makeReactionsPublicDescription: "將您做過的回應設為公開可見。" +makeReactionsPublic: "將反應設為公開" +makeReactionsPublicDescription: "將您做過的反應設為公開可見。" classic: "經典" muteThread: "將貼文串設為靜音" unmuteThread: "將貼文串的靜音解除" @@ -869,6 +869,32 @@ logoutConfirm: "確定要登出嗎?" lastActiveDate: "上次使用日期及時間" statusbar: "狀態列" pleaseSelect: "請選擇" +reverse: "翻轉" +colored: "彩色" +refreshInterval: "更新間隔" +label: "標籤" +type: "類型" +speed: "速度" +slow: "慢" +fast: "快" +sensitiveMediaDetection: "敏感性媒體的檢測" +localOnly: "僅限本地" +remoteOnly: "僅限遠端" +failedToUpload: "上傳失敗" +cannotUploadBecauseInappropriate: "由於判定可能包含不適當的內容,因此無法上船。" +cannotUploadBecauseNoFreeSpace: "由於雲端硬碟沒有可用空間,因此無法上船>" +beta: "Beta" +enableAutoSensitive: "自動NSFW判定" +enableAutoSensitiveDescription: "如果可用,請利用機器學習在媒體上自動設置 NSFW 旗標。 即使關閉此功能,依實例而定也可能會自動設置。" +activeEmailValidationDescription: "積極地驗證用戶的電子郵件地址,判斷它是否為免洗地址,或者它是否可以通信。 若關閉,則只會檢查字元是否正確。" +_sensitiveMediaDetection: + description: "您可以使用機器學習自動檢測敏感媒體並將其用於審核。 伺服器的負荷會稍微增加。" + sensitivity: "檢測敏感度" + sensitivityDescription: "敏感度低時,誤檢測(偽陽性)會減少。敏感度高時,漏檢(偽陰性)會減少。" + setSensitiveFlagAutomatically: "設定 NSFW 旗標" + setSensitiveFlagAutomaticallyDescription: "即使將此設定關閉,判定結果也會保留在內部。" + analyzeVideos: "啟用影片分析" + analyzeVideosDescription: "除了靜止影像以外,也分析影片。伺服器的負荷會稍微增加。" _emailUnavailable: used: "已經在使用中" format: "格式無效" diff --git a/package.json b/package.json index 402ae906d0..93df550f84 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "12.112.3", + "version": "12.113.0", "codename": "indigo", "repository": { "type": "git", @@ -41,7 +41,7 @@ "devDependencies": { "@types/gulp": "4.0.9", "@types/gulp-rename": "2.0.1", - "@typescript-eslint/parser": "5.30.0", + "@typescript-eslint/parser": "5.30.6", "cross-env": "7.0.3", "cypress": "10.3.0", "start-server-and-test": "1.14.0", diff --git a/packages/backend/package.json b/packages/backend/package.json index b50aa601d9..b91f5fc32f 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -13,6 +13,9 @@ "chokidar": "^3.3.1", "lodash": "^4.17.21" }, + "optionalDependencies": { + "@tensorflow/tfjs-node": "3.18.0" + }, "dependencies": { "@bull-board/koa": "4.0.0", "@discordapp/twemoji": "14.0.2", @@ -23,7 +26,6 @@ "@peertube/http-signature": "1.6.0", "@sinonjs/fake-timers": "9.1.2", "@syuilo/aiscript": "0.11.1", - "@tensorflow/tfjs-node": "3.18.0", "abort-controller": "3.0.0", "ajv": "8.11.0", "archiver": "5.3.1", @@ -37,7 +39,7 @@ "cbor": "8.1.0", "chalk": "5.0.1", "chalk-template": "0.4.0", - "chokidar": "3.3.1", + "chokidar": "3.5.3", "cli-highlight": "2.1.11", "color-convert": "2.0.1", "content-disposition": "0.5.4", @@ -67,15 +69,15 @@ "koa-send": "5.0.1", "koa-slow": "2.1.0", "koa-views": "7.0.2", - "mfm-js": "0.22.1", + "mfm-js": "0.23.0-canary.1", "mime-types": "2.1.35", "misskey-js": "0.0.14", "mocha": "10.0.0", "ms": "3.0.0-canary.1", "multer": "1.4.4", "nested-property": "4.0.0", - "node-fetch": "3.2.6", - "nodemailer": "6.7.6", + "node-fetch": "3.2.8", + "nodemailer": "6.7.7", "nsfwjs": "2.4.1", "os-utils": "0.0.14", "parse5": "7.0.0", @@ -106,11 +108,11 @@ "style-loader": "3.3.1", "summaly": "2.7.0", "syslog-pro": "1.0.0", - "systeminformation": "5.11.22", + "systeminformation": "5.12.0", "tinycolor2": "1.4.2", "tmp": "0.2.1", "ts-loader": "9.3.1", - "ts-node": "10.8.1", + "ts-node": "10.8.2", "tsc-alias": "1.6.11", "tsconfig-paths": "4.0.0", "twemoji-parser": "14.0.0", @@ -135,7 +137,7 @@ "@types/jsdom": "16.2.14", "@types/jsonld": "1.5.6", "@types/jsrsasign": "10.5.1", - "@types/koa": "2.13.4", + "@types/koa": "2.13.5", "@types/koa-bodyparser": "4.3.7", "@types/koa-cors": "0.0.2", "@types/koa-favicon": "2.0.21", @@ -147,7 +149,7 @@ "@types/koa__multer": "2.0.4", "@types/koa__router": "8.0.11", "@types/mocha": "9.1.1", - "@types/node": "18.0.0", + "@types/node": "18.0.3", "@types/node-fetch": "3.0.3", "@types/nodemailer": "6.4.4", "@types/oauth": "0.9.1", @@ -169,10 +171,10 @@ "@types/web-push": "3.3.2", "@types/websocket": "1.0.5", "@types/ws": "8.5.3", - "@typescript-eslint/eslint-plugin": "5.30.0", - "@typescript-eslint/parser": "5.30.0", + "@typescript-eslint/eslint-plugin": "5.30.6", + "@typescript-eslint/parser": "5.30.6", "cross-env": "7.0.3", - "eslint": "8.18.0", + "eslint": "8.19.0", "eslint-plugin-import": "2.26.0", "execa": "6.1.0", "typescript": "4.7.4" diff --git a/packages/backend/src/mfm/to-html.ts b/packages/backend/src/mfm/to-html.ts index 5b382063eb..bcb5c86a3d 100644 --- a/packages/backend/src/mfm/to-html.ts +++ b/packages/backend/src/mfm/to-html.ts @@ -145,6 +145,12 @@ export function toHtml(nodes: mfm.MfmNode[] | null, mentionedRemoteUsers: IMenti a.textContent = node.props.content; return a; }, + + plain(node) { + const el = doc.createElement('span'); + appendChildren(node.children, el); + return el; + }, }; appendChildren(nodes, doc.body); diff --git a/packages/backend/src/queue/processors/db/export-custom-emojis.ts b/packages/backend/src/queue/processors/db/export-custom-emojis.ts index 8ce1d05272..3da887cda2 100644 --- a/packages/backend/src/queue/processors/db/export-custom-emojis.ts +++ b/packages/backend/src/queue/processors/db/export-custom-emojis.ts @@ -8,7 +8,7 @@ import { queueLogger } from '../../logger.js'; import { addFile } from '@/services/drive/add-file.js'; import { format as dateFormat } from 'date-fns'; import { Users, Emojis } from '@/models/index.js'; -import { } from '@/queue/types.js'; +import { } from '@/queue/types.js'; import { createTemp, createTempDir } from '@/misc/create-temp.js'; import { downloadUrl } from '@/misc/download-url.js'; import config from '@/config/index.js'; diff --git a/packages/backend/src/remote/activitypub/models/question.ts b/packages/backend/src/remote/activitypub/models/question.ts index 034501572a..f0321fdf2f 100644 --- a/packages/backend/src/remote/activitypub/models/question.ts +++ b/packages/backend/src/remote/activitypub/models/question.ts @@ -1,6 +1,6 @@ import config from '@/config/index.js'; import Resolver from '../resolver.js'; -import { IObject, IQuestion, isQuestion } from '../type.js'; +import { IObject, IQuestion, isQuestion } from '../type.js'; import { apLogger } from '../logger.js'; import { Notes, Polls } from '@/models/index.js'; import { IPoll } from '@/models/entities/poll.js'; diff --git a/packages/backend/src/remote/activitypub/renderer/like.ts b/packages/backend/src/remote/activitypub/renderer/like.ts index da1bfe6e8e..00fb72e8a3 100644 --- a/packages/backend/src/remote/activitypub/renderer/like.ts +++ b/packages/backend/src/remote/activitypub/renderer/like.ts @@ -8,7 +8,7 @@ import renderEmoji from './emoji.js'; export const renderLike = async (noteReaction: NoteReaction, note: Note) => { const reaction = noteReaction.reaction; - const object = { + const object = { type: 'Like', id: `${config.url}/likes/${noteReaction.id}`, actor: `${config.url}/users/${noteReaction.userId}`, diff --git a/packages/backend/src/server/api/api-handler.ts b/packages/backend/src/server/api/api-handler.ts index 34ff970b4c..ec71ddd2c0 100644 --- a/packages/backend/src/server/api/api-handler.ts +++ b/packages/backend/src/server/api/api-handler.ts @@ -68,11 +68,11 @@ export default (endpoint: IEndpoint, ctx: Koa.Context) => new Promise<void>((res } try { - UserIps.insert({ + UserIps.createQueryBuilder().insert().values({ createdAt: new Date(), userId: user.id, ip: ip, - }); + }).orIgnore(true).execute(); } catch { } } diff --git a/packages/backend/src/server/api/common/read-notification.ts b/packages/backend/src/server/api/common/read-notification.ts index 17dd8e6f02..cf993ade3e 100644 --- a/packages/backend/src/server/api/common/read-notification.ts +++ b/packages/backend/src/server/api/common/read-notification.ts @@ -12,13 +12,15 @@ export async function readNotification( if (notificationIds.length === 0) return; // Update documents - await Notifications.update({ + const result = await Notifications.update({ id: In(notificationIds), isRead: false, }, { isRead: true, }); + if (result.affected === 0) return; + if (!await Users.getHasUnreadNotification(userId)) return postReadAllNotifications(userId); else return postReadNotifications(userId, notificationIds); } diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index 122120f275..3c2f1cea0d 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -214,7 +214,7 @@ export default define(meta, paramDef, async (ps, _user, token) => { const newDescription = profileUpdates.description === undefined ? profile.description : profileUpdates.description; if (newName != null) { - const tokens = mfm.parsePlain(newName); + const tokens = mfm.parseSimple(newName); emojis = emojis.concat(extractCustomEmojisFromMfm(tokens!)); } diff --git a/packages/backend/src/server/nodeinfo.ts b/packages/backend/src/server/nodeinfo.ts index 13a362a75f..f139d203d2 100644 --- a/packages/backend/src/server/nodeinfo.ts +++ b/packages/backend/src/server/nodeinfo.ts @@ -78,6 +78,7 @@ const nodeinfo2 = async () => { enableEmail: meta.enableEmail, enableServiceWorker: meta.enableServiceWorker, proxyAccountName: proxyAccount ? proxyAccount.username : null, + themeColor: meta.themeColor || '#86b300', }, }; }; diff --git a/packages/backend/src/services/detect-sensitive.ts b/packages/backend/src/services/detect-sensitive.ts index 0fa263599b..2ade39d524 100644 --- a/packages/backend/src/services/detect-sensitive.ts +++ b/packages/backend/src/services/detect-sensitive.ts @@ -2,19 +2,34 @@ import * as fs from 'node:fs'; import { fileURLToPath } from 'node:url'; import { dirname } from 'node:path'; import * as nsfw from 'nsfwjs'; -import * as tf from '@tensorflow/tfjs-node'; +import si from 'systeminformation'; const _filename = fileURLToPath(import.meta.url); const _dirname = dirname(_filename); +const REQUIRED_CPU_FLAGS = ['avx2', 'fma']; +let isSupportedCpu: undefined | boolean = undefined; + let model: nsfw.NSFWJS; export async function detectSensitive(path: string): Promise<nsfw.predictionType[] | null> { try { + if (isSupportedCpu === undefined) { + const cpuFlags = await getCpuFlags(); + isSupportedCpu = REQUIRED_CPU_FLAGS.every(required => cpuFlags.includes(required)); + } + + if (!isSupportedCpu) { + console.error('This CPU cannot use TensorFlow.'); + return null; + } + + const tf = await import('@tensorflow/tfjs-node'); + if (model == null) model = await nsfw.load(`file://${_dirname}/../../nsfw-model/`, { size: 299 }); const buffer = await fs.promises.readFile(path); - const image = await tf.node.decodeImage(buffer, 3) as tf.Tensor3D; + const image = await tf.node.decodeImage(buffer, 3) as any; try { const predictions = await model.classify(image); return predictions; @@ -26,3 +41,8 @@ export async function detectSensitive(path: string): Promise<nsfw.predictionType return null; } } + +async function getCpuFlags(): Promise<string[]> { + const str = await si.cpuFlags(); + return str.split(/\s+/); +} diff --git a/packages/backend/src/services/fetch-instance-metadata.ts b/packages/backend/src/services/fetch-instance-metadata.ts index 029c388dc2..ee1245132a 100644 --- a/packages/backend/src/services/fetch-instance-metadata.ts +++ b/packages/backend/src/services/fetch-instance-metadata.ts @@ -34,7 +34,7 @@ export async function fetchInstanceMetadata(instance: Instance, force = false): const [favicon, icon, themeColor, name, description] = await Promise.all([ fetchFaviconUrl(instance, dom).catch(() => null), fetchIconUrl(instance, dom, manifest).catch(() => null), - getThemeColor(dom, manifest).catch(() => null), + getThemeColor(info, dom, manifest).catch(() => null), getSiteName(info, dom, manifest).catch(() => null), getDescription(info, dom, manifest).catch(() => null), ]); @@ -208,8 +208,8 @@ async function fetchIconUrl(instance: Instance, doc: DOMWindow['document'] | nul return null; } -async function getThemeColor(doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> { - const themeColor = doc?.querySelector('meta[name="theme-color"]')?.getAttribute('content') || manifest?.theme_color; +async function getThemeColor(info: NodeInfo | null, doc: DOMWindow['document'] | null, manifest: Record<string, any> | null): Promise<string | null> { + const themeColor = info?.metadata?.themeColor || doc?.querySelector('meta[name="theme-color"]')?.getAttribute('content') || manifest?.theme_color; if (themeColor) { const color = new tinycolor(themeColor); diff --git a/packages/backend/src/services/push-notification.ts b/packages/backend/src/services/push-notification.ts index 5c3bafbb34..393a23d050 100644 --- a/packages/backend/src/services/push-notification.ts +++ b/packages/backend/src/services/push-notification.ts @@ -64,6 +64,7 @@ export async function pushNotification<T extends keyof pushNotificationsTypes>(u type, body: type === 'notification' ? truncateNotification(body as Packed<'Notification'>) : body, userId, + dateTime: (new Date()).getTime(), }), { proxy: config.proxy, }).catch((err: any) => { diff --git a/packages/backend/yarn.lock b/packages/backend/yarn.lock index a2090a5e94..dea6c38343 100644 --- a/packages/backend/yarn.lock +++ b/packages/backend/yarn.lock @@ -730,10 +730,10 @@ "@types/koa-compose" "*" "@types/node" "*" -"@types/koa@2.13.4": - version "2.13.4" - resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.13.4.tgz#10620b3f24a8027ef5cbae88b393d1b31205726b" - integrity sha512-dfHYMfU+z/vKtQB7NUrthdAEiSvnLebvBjwHtfFmpZmB7em2N3WVQdHgnFq+xvyVgxW5jKDmjWfLD3lw4g4uTw== +"@types/koa@2.13.5": + version "2.13.5" + resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.13.5.tgz#64b3ca4d54e08c0062e89ec666c9f45443b21a61" + integrity sha512-HSUOdzKz3by4fnqagwthW/1w/yJspTgppyyalPVbgZf8jQWvdIXcVW5h2DGtw4zYntOaeRGx49r1hxoPWrD4aA== dependencies: "@types/accepts" "*" "@types/content-disposition" "*" @@ -800,10 +800,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.6.2.tgz#331b7b9f8621c638284787c5559423822fdffc50" integrity sha512-LSw8TZt12ZudbpHc6EkIyDM3nHVWKYrAvGy6EAJfNfjusbwnThqjqxUKKRwuV3iWYeW/LYMzNgaq3MaLffQ2xA== -"@types/node@18.0.0": - version "18.0.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.0.tgz#67c7b724e1bcdd7a8821ce0d5ee184d3b4dd525a" - integrity sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA== +"@types/node@18.0.3": + version "18.0.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.3.tgz#463fc47f13ec0688a33aec75d078a0541a447199" + integrity sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ== "@types/node@^14.11.8": version "14.17.9" @@ -994,14 +994,14 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.0.tgz#524a11e15c09701733033c96943ecf33f55d9ca1" - integrity sha512-lvhRJ2pGe2V9MEU46ELTdiHgiAFZPKtLhiU5wlnaYpMc2+c1R8fh8i80ZAa665drvjHKUJyRRGg3gEm1If54ow== +"@typescript-eslint/eslint-plugin@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.6.tgz#9c6017b6c1d04894141b4a87816388967f64c359" + integrity sha512-J4zYMIhgrx4MgnZrSDD7sEnQp7FmhKNOaqaOpaoQ/SfdMfRB/0yvK74hTnvH+VQxndZynqs5/Hn4t+2/j9bADg== dependencies: - "@typescript-eslint/scope-manager" "5.30.0" - "@typescript-eslint/type-utils" "5.30.0" - "@typescript-eslint/utils" "5.30.0" + "@typescript-eslint/scope-manager" "5.30.6" + "@typescript-eslint/type-utils" "5.30.6" + "@typescript-eslint/utils" "5.30.6" debug "^4.3.4" functional-red-black-tree "^1.0.1" ignore "^5.2.0" @@ -1009,69 +1009,69 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/parser@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.30.0.tgz#a2184fb5f8ef2bf1db0ae61a43907e2e32aa1b8f" - integrity sha512-2oYYUws5o2liX6SrFQ5RB88+PuRymaM2EU02/9Ppoyu70vllPnHVO7ioxDdq/ypXHA277R04SVjxvwI8HmZpzA== +"@typescript-eslint/parser@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.30.6.tgz#add440db038fa9d777e4ebdaf66da9e7fb7abe92" + integrity sha512-gfF9lZjT0p2ZSdxO70Xbw8w9sPPJGfAdjK7WikEjB3fcUI/yr9maUVEdqigBjKincUYNKOmf7QBMiTf719kbrA== dependencies: - "@typescript-eslint/scope-manager" "5.30.0" - "@typescript-eslint/types" "5.30.0" - "@typescript-eslint/typescript-estree" "5.30.0" + "@typescript-eslint/scope-manager" "5.30.6" + "@typescript-eslint/types" "5.30.6" + "@typescript-eslint/typescript-estree" "5.30.6" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.30.0.tgz#bf585ee801ab4ad84db2f840174e171a6bb002c7" - integrity sha512-3TZxvlQcK5fhTBw5solQucWSJvonXf5yua5nx8OqK94hxdrT7/6W3/CS42MLd/f1BmlmmbGEgQcTHHCktUX5bQ== +"@typescript-eslint/scope-manager@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.30.6.tgz#ce1b49ff5ce47f55518d63dbe8fc9181ddbd1a33" + integrity sha512-Hkq5PhLgtVoW1obkqYH0i4iELctEKixkhWLPTYs55doGUKCASvkjOXOd/pisVeLdO24ZX9D6yymJ/twqpJiG3g== dependencies: - "@typescript-eslint/types" "5.30.0" - "@typescript-eslint/visitor-keys" "5.30.0" + "@typescript-eslint/types" "5.30.6" + "@typescript-eslint/visitor-keys" "5.30.6" -"@typescript-eslint/type-utils@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.30.0.tgz#98f3af926a5099153f092d4dad87148df21fbaae" - integrity sha512-GF8JZbZqSS+azehzlv/lmQQ3EU3VfWYzCczdZjJRxSEeXDQkqFhCBgFhallLDbPwQOEQ4MHpiPfkjKk7zlmeNg== +"@typescript-eslint/type-utils@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.30.6.tgz#a64aa9acbe609ab77f09f53434a6af2b9685f3af" + integrity sha512-GFVVzs2j0QPpM+NTDMXtNmJKlF842lkZKDSanIxf+ArJsGeZUIaeT4jGg+gAgHt7AcQSFwW7htzF/rbAh2jaVA== dependencies: - "@typescript-eslint/utils" "5.30.0" + "@typescript-eslint/utils" "5.30.6" debug "^4.3.4" tsutils "^3.21.0" -"@typescript-eslint/types@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.30.0.tgz#db7d81d585a3da3801432a9c1d2fafbff125e110" - integrity sha512-vfqcBrsRNWw/LBXyncMF/KrUTYYzzygCSsVqlZ1qGu1QtGs6vMkt3US0VNSQ05grXi5Yadp3qv5XZdYLjpp8ag== +"@typescript-eslint/types@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.30.6.tgz#86369d0a7af8c67024115ac1da3e8fb2d38907e1" + integrity sha512-HdnP8HioL1F7CwVmT4RaaMX57RrfqsOMclZc08wGMiDYJBsLGBM7JwXM4cZJmbWLzIR/pXg1kkrBBVpxTOwfUg== -"@typescript-eslint/typescript-estree@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.0.tgz#4565ee8a6d2ac368996e20b2344ea0eab1a8f0bb" - integrity sha512-hDEawogreZB4n1zoqcrrtg/wPyyiCxmhPLpZ6kmWfKF5M5G0clRLaEexpuWr31fZ42F96SlD/5xCt1bT5Qm4Nw== +"@typescript-eslint/typescript-estree@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.6.tgz#a84a0d6a486f9b54042da1de3d671a2c9f14484e" + integrity sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A== dependencies: - "@typescript-eslint/types" "5.30.0" - "@typescript-eslint/visitor-keys" "5.30.0" + "@typescript-eslint/types" "5.30.6" + "@typescript-eslint/visitor-keys" "5.30.6" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/utils@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.30.0.tgz#1dac771fead5eab40d31860716de219356f5f754" - integrity sha512-0bIgOgZflLKIcZsWvfklsaQTM3ZUbmtH0rJ1hKyV3raoUYyeZwcjQ8ZUJTzS7KnhNcsVT1Rxs7zeeMHEhGlltw== +"@typescript-eslint/utils@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.30.6.tgz#1de2da14f678e7d187daa6f2e4cdb558ed0609dc" + integrity sha512-xFBLc/esUbLOJLk9jKv0E9gD/OH966M40aY9jJ8GiqpSkP2xOV908cokJqqhVd85WoIvHVHYXxSFE4cCSDzVvA== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.30.0" - "@typescript-eslint/types" "5.30.0" - "@typescript-eslint/typescript-estree" "5.30.0" + "@typescript-eslint/scope-manager" "5.30.6" + "@typescript-eslint/types" "5.30.6" + "@typescript-eslint/typescript-estree" "5.30.6" eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/visitor-keys@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.0.tgz#07721d23daca2ec4c2da7f1e660d41cd78bacac3" - integrity sha512-6WcIeRk2DQ3pHKxU1Ni0qMXJkjO/zLjBymlYBy/53qxe7yjEFSvzKLDToJjURUhSl2Fzhkl4SMXQoETauF74cw== +"@typescript-eslint/visitor-keys@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.6.tgz#94dd10bb481c8083378d24de1742a14b38a2678c" + integrity sha512-41OiCjdL2mCaSDi2SvYbzFLlqqlm5v1ZW9Ym55wXKL/Rx6OOB1IbuFGo71Fj6Xy90gJDFTlgOS+vbmtGHPTQQA== dependencies: - "@typescript-eslint/types" "5.30.0" + "@typescript-eslint/types" "5.30.6" eslint-visitor-keys "^3.3.0" "@ungap/promise-all-settled@1.1.2": @@ -1278,6 +1278,14 @@ anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" +anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + app-root-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad" @@ -1878,7 +1886,7 @@ cheerio@0.22.0: lodash.reject "^4.4.0" lodash.some "^4.4.0" -chokidar@3.3.1, chokidar@3.5.3, chokidar@^3.3.1, chokidar@^3.5.3: +chokidar@3.5.3, chokidar@^3.3.1, chokidar@^3.5.3: version "3.3.1" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.1.tgz#c84e5b3d18d9a4d77558fef466b1bf16bbeb3450" integrity sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg== @@ -2882,10 +2890,10 @@ eslint-visitor-keys@^3.3.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@8.18.0: - version "8.18.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.18.0.tgz#78d565d16c993d0b73968c523c0446b13da784fd" - integrity sha512-As1EfFMVk7Xc6/CvhssHUjsAQSkpfXvUGMFC3ce8JDe6WvqCgRrLOBQbVpsBFr1X1V+RACOadnzVvcUS5ni2bA== +eslint@8.19.0: + version "8.19.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.19.0.tgz#7342a3cbc4fbc5c106a1eefe0fd0b50b6b1a7d28" + integrity sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw== dependencies: "@eslint/eslintrc" "^1.3.0" "@humanwhocodes/config-array" "^0.9.2" @@ -3281,6 +3289,11 @@ fsevents@~2.1.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + fstream@^1.0.12: version "1.0.12" resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" @@ -3417,7 +3430,7 @@ github-from-package@0.0.0: resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4= -glob-parent@^5.1.0, glob-parent@^5.1.2, glob-parent@~5.1.0: +glob-parent@^5.1.0, glob-parent@^5.1.2, glob-parent@~5.1.0, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -4856,12 +4869,12 @@ methods@^1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= -mfm-js@0.22.1: - version "0.22.1" - resolved "https://registry.yarnpkg.com/mfm-js/-/mfm-js-0.22.1.tgz#ad5f0b95cc903ca5a5e414e2edf64ac4648dc8c2" - integrity sha512-UV5zvDKlWPpBFeABhyCzuOTJ3RwrNrmVpJ+zz/dFX6D/ntEywljgxkfsLamcy0ZSwUAr0O+WQxGHvAwyxUgsAQ== +mfm-js@0.23.0-canary.1: + version "0.23.0-canary.1" + resolved "https://registry.yarnpkg.com/mfm-js/-/mfm-js-0.23.0-canary.1.tgz#1b7b7635f18bed9776054406b72e6bd613c8d0eb" + integrity sha512-SkMrW1rQAv+mFGtLKN9DSv6vxSREDu8ChmkBl1Ch5sQfp47BhuvcRg5EKGmt3WAQRAOylXYMg8wVYR7C5BHKeA== dependencies: - twemoji-parser "14.0.x" + twemoji-parser "14.0.0" micromatch@^4.0.0, micromatch@^4.0.2: version "4.0.2" @@ -5283,10 +5296,10 @@ node-fetch@*: fetch-blob "^3.1.4" formdata-polyfill "^4.0.10" -node-fetch@3.2.6, node-fetch@^3.2.2: - version "3.2.6" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.2.6.tgz#6d4627181697a9d9674aae0d61548e0d629b31b9" - integrity sha512-LAy/HZnLADOVkVPubaxHDft29booGglPFDr2Hw0J1AercRh01UiVFm++KMDnJeH9sHgNB4hsXPii7Sgym/sTbw== +node-fetch@3.2.8: + version "3.2.8" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.2.8.tgz#0d9516dcf43a758d78d6dbe538adf0b1f6a4944e" + integrity sha512-KtpD1YhGszhntMpBDyp5lyagk8KIMopC1LEb7cQUAh7zcosaX5uK8HnbNb2i3NTQK3sIawCItS0uFC3QzcLHdg== dependencies: data-uri-to-buffer "^4.0.0" fetch-blob "^3.1.4" @@ -5299,6 +5312,15 @@ node-fetch@^2.6.1, node-fetch@~2.6.1: dependencies: whatwg-url "^5.0.0" +node-fetch@^3.2.2: + version "3.2.6" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.2.6.tgz#6d4627181697a9d9674aae0d61548e0d629b31b9" + integrity sha512-LAy/HZnLADOVkVPubaxHDft29booGglPFDr2Hw0J1AercRh01UiVFm++KMDnJeH9sHgNB4hsXPii7Sgym/sTbw== + dependencies: + data-uri-to-buffer "^4.0.0" + fetch-blob "^3.1.4" + formdata-polyfill "^4.0.10" + node-gyp-build@^4.2.3: version "4.3.0" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" @@ -5325,10 +5347,10 @@ node-gyp@^9.0.0: tar "^6.1.2" which "^2.0.2" -nodemailer@6.7.6: - version "6.7.6" - resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.7.6.tgz#d3de8f644eaa0dad784d1be1375c596de492f3fc" - integrity sha512-/6KF/umU7r7X21Y648/yiRLrgkfz0dmpyuo4BfgYWIpnT/jCbkPTvegMfxCsDAu+O810p2L1BGXieMTPp3nJVA== +nodemailer@6.7.7: + version "6.7.7" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.7.7.tgz#e522fbd7507b81c51446d3f79c4603bf00083ddd" + integrity sha512-pOLC/s+2I1EXuSqO5Wa34i3kXZG3gugDssH+ZNCevHad65tc8vQlCQpOLaUjopvkRQKm2Cki2aME7fEOPRy3bA== nofilter@^2.0.3: version "2.0.3" @@ -6263,6 +6285,13 @@ readdirp@~3.3.0: dependencies: picomatch "^2.0.7" +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + reconnecting-websocket@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/reconnecting-websocket/-/reconnecting-websocket-4.4.0.tgz#3b0e5b96ef119e78a03135865b8bb0af1b948783" @@ -7006,10 +7035,10 @@ syslog-pro@1.0.0: dependencies: moment "^2.22.2" -systeminformation@5.11.22: - version "5.11.22" - resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.11.22.tgz#52eb78fd6bb48eef372f502b494ff59aacf82c02" - integrity sha512-sBZJ/WBCf2vDLeMZaEyVuo+aXylOSmNHHB2cX0jHULFxSBLXHX+QUHYrCvmz+YiflKY3bsahVWX7vwuz1p1QZA== +systeminformation@5.12.0: + version "5.12.0" + resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.12.0.tgz#1ff8d0b0fef9c2a6f70e1b1f2e681b8cd2d4b78e" + integrity sha512-2fa/2cnWxiC/g8v3XX4aEC2CQWl/WJ+JrfLq9f76lxYqkW4DWiU3vJhrEgAzBT07ta73c5wHd0xgMeMo0vBiMQ== tapable@^2.2.0: version "2.2.0" @@ -7203,10 +7232,10 @@ ts-loader@9.3.1: micromatch "^4.0.0" semver "^7.3.4" -ts-node@10.8.1: - version "10.8.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.8.1.tgz#ea2bd3459011b52699d7e88daa55a45a1af4f066" - integrity sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g== +ts-node@10.8.2: + version "10.8.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.8.2.tgz#3185b75228cef116bf82ffe8762594f54b2a23f2" + integrity sha512-LYdGnoGddf1D6v8REPtIH+5iq/gTDuZqv2/UJUU7tKjuEU8xVZorBM+buCGNjj+pGEud+sOoM4CX3/YzINpENA== dependencies: "@cspotcode/source-map-support" "^0.8.0" "@tsconfig/node10" "^1.0.7" @@ -7287,7 +7316,7 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= -twemoji-parser@14.0.0, twemoji-parser@14.0.x: +twemoji-parser@14.0.0: version "14.0.0" resolved "https://registry.yarnpkg.com/twemoji-parser/-/twemoji-parser-14.0.0.tgz#13dabcb6d3a261d9efbf58a1666b182033bf2b62" integrity sha512-9DUOTGLOWs0pFWnh1p6NF+C3CkQ96PWmEFwhOVmT3WbecRC+68AIqpsnJXygfkFcp4aXbOp8Dwbhh/HQgvoRxA== diff --git a/packages/client/package.json b/packages/client/package.json index f65e70870e..8d2efd0b92 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -15,7 +15,7 @@ "@rollup/plugin-alias": "3.1.9", "@rollup/plugin-json": "4.1.0", "@syuilo/aiscript": "0.11.1", - "@vitejs/plugin-vue": "3.0.0-beta.1", + "@vitejs/plugin-vue": "3.0.0", "@vue/compiler-sfc": "3.2.37", "abort-controller": "3.0.0", "autobind-decorator": "2.4.0", @@ -40,7 +40,7 @@ "json5": "2.2.1", "katex": "0.15.6", "matter-js": "0.18.0", - "mfm-js": "0.22.1", + "mfm-js": "0.23.0-canary.1", "misskey-js": "0.0.14", "mocha": "10.0.0", "ms": "2.1.3", @@ -56,7 +56,7 @@ "random-seed": "0.3.0", "reflect-metadata": "0.1.13", "rndstr": "1.0.0", - "rollup": "2.75.7", + "rollup": "2.76.0", "s-age": "1.1.2", "sass": "1.53.0", "seedrandom": "3.0.5", @@ -74,7 +74,7 @@ "uuid": "8.3.2", "v-debounce": "0.1.2", "vanilla-tilt": "1.7.2", - "vite": "3.0.0-beta.7", + "vite": "3.0.0", "vue": "3.2.37", "vue-prism-editor": "2.0.0-alpha.2", "vuedraggable": "4.0.1", @@ -100,13 +100,13 @@ "@types/uuid": "8.3.4", "@types/websocket": "1.0.5", "@types/ws": "8.5.3", - "@typescript-eslint/eslint-plugin": "5.30.0", - "@typescript-eslint/parser": "5.30.0", + "@typescript-eslint/eslint-plugin": "5.30.6", + "@typescript-eslint/parser": "5.30.6", "cross-env": "7.0.3", "cypress": "10.3.0", - "eslint": "8.18.0", + "eslint": "8.19.0", "eslint-plugin-import": "2.26.0", - "eslint-plugin-vue": "9.1.1", + "eslint-plugin-vue": "9.2.0", "start-server-and-test": "1.14.0" } } diff --git a/packages/client/src/components/chart.vue b/packages/client/src/components/chart.vue index fc7c4ff950..31e95404fa 100644 --- a/packages/client/src/components/chart.vue +++ b/packages/client/src/components/chart.vue @@ -316,7 +316,7 @@ const render = () => { plugins: [{ id: 'vLine', beforeDraw(chart, args, options) { - if (chart.tooltip._active && chart.tooltip._active.length) { + if (chart.tooltip?._active?.length) { const activePoint = chart.tooltip._active[0]; const ctx = chart.ctx; const x = activePoint.element.x; diff --git a/packages/client/src/components/drive-file-thumbnail.vue b/packages/client/src/components/drive-file-thumbnail.vue index 16c77f7267..b346585cec 100644 --- a/packages/client/src/components/drive-file-thumbnail.vue +++ b/packages/client/src/components/drive-file-thumbnail.vue @@ -59,7 +59,7 @@ const isThumbnailAvailable = computed(() => { display: flex; background: var(--panel); border-radius: 8px; - overflow: hidden; overflow: clip; + overflow: clip; > .icon-sub { position: absolute; diff --git a/packages/client/src/components/drive-window.vue b/packages/client/src/components/drive-window.vue index 5bbfca83c9..51ea2b5015 100644 --- a/packages/client/src/components/drive-window.vue +++ b/packages/client/src/components/drive-window.vue @@ -13,7 +13,7 @@ </template> <script lang="ts" setup> -import { } from 'vue'; +import { } from 'vue'; import * as Misskey from 'misskey-js'; import XDrive from './drive.vue'; import XWindow from '@/components/ui/window.vue'; diff --git a/packages/client/src/components/form/input.vue b/packages/client/src/components/form/input.vue index ec1ad20de3..1cc3912178 100644 --- a/packages/client/src/components/form/input.vue +++ b/packages/client/src/components/form/input.vue @@ -41,7 +41,7 @@ import { useInterval } from '@/scripts/use-interval'; const props = defineProps<{ modelValue: string | number; - type?: 'text' | 'number' | 'password' | 'email' | 'url' | 'date' | 'time'; + type?: 'text' | 'number' | 'password' | 'email' | 'url' | 'date' | 'time' | 'search'; required?: boolean; readonly?: boolean; disabled?: boolean; diff --git a/packages/client/src/components/form/range.vue b/packages/client/src/components/form/range.vue index ebec482d84..8301d27830 100644 --- a/packages/client/src/components/form/range.vue +++ b/packages/client/src/components/form/range.vue @@ -189,7 +189,7 @@ const onMousedown = (ev: MouseEvent | TouchEvent) => { height: 3px; background: rgba(0, 0, 0, 0.1); border-radius: 999px; - overflow: hidden; overflow: clip; + overflow: clip; > .highlight { position: absolute; diff --git a/packages/client/src/components/global/url.vue b/packages/client/src/components/global/url.vue index 34ba9024cc..dc79a20649 100644 --- a/packages/client/src/components/global/url.vue +++ b/packages/client/src/components/global/url.vue @@ -1,5 +1,6 @@ <template> -<component :is="self ? 'MkA' : 'a'" ref="el" class="ieqqeuvs _link" :[attr]="self ? url.substr(local.length) : url" :rel="rel" :target="target" +<component + :is="self ? 'MkA' : 'a'" ref="el" class="ieqqeuvs _link" :[attr]="self ? url.substr(local.length) : url" :rel="rel" :target="target" @contextmenu.stop="() => {}" > <template v-if="!self"> @@ -23,14 +24,7 @@ import { toUnicode as decodePunycode } from 'punycode/'; import { url as local } from '@/config'; import * as os from '@/os'; import { useTooltip } from '@/scripts/use-tooltip'; - -function safeURIDecode(str: string) { - try { - return decodeURIComponent(str); - } catch { - return str; - } -} +import { safeURIDecode } from '@/scripts/safe-uri-decode'; export default defineComponent({ props: { @@ -42,7 +36,7 @@ export default defineComponent({ type: String, required: false, default: null, - } + }, }, setup(props) { const self = props.url.startsWith(local); diff --git a/packages/client/src/components/marquee.vue b/packages/client/src/components/marquee.vue index ad9de9b845..5ca04b0b48 100644 --- a/packages/client/src/components/marquee.vue +++ b/packages/client/src/components/marquee.vue @@ -76,7 +76,7 @@ export default { <style lang="scss" module> .wrap { - overflow: hidden; overflow: clip; + overflow: clip; animation-play-state: running; &:hover { diff --git a/packages/client/src/components/mention.vue b/packages/client/src/components/mention.vue index 2c8bc0c04e..cf69437771 100644 --- a/packages/client/src/components/mention.vue +++ b/packages/client/src/components/mention.vue @@ -1,15 +1,15 @@ <template> -<MkA v-if="url.startsWith('/')" v-user-preview="canonical" :class="[$style.root, { isMe }]" :to="url" :style="{ background: bgCss }"> - <img :class="$style.icon" :src="`/avatar/@${username}@${host}`" alt=""> +<MkA v-if="url.startsWith('/')" v-user-preview="canonical" class="akbvjaqn" :class="{ isMe }" :to="url" :style="{ background: bgCss }"> + <img class="icon" :src="`/avatar/@${username}@${host}`" alt=""> <span class="main"> <span class="username">@{{ username }}</span> - <span v-if="(host != localHost) || $store.state.showFullAcct" :class="$style.mainHost">@{{ toUnicode(host) }}</span> + <span v-if="(host != localHost) || $store.state.showFullAcct" class="host">@{{ toUnicode(host) }}</span> </span> </MkA> -<a v-else :class="$style.root" :href="url" target="_blank" rel="noopener" :style="{ background: bgCss }"> +<a v-else class="akbvjaqn" :href="url" target="_blank" rel="noopener" :style="{ background: bgCss }"> <span class="main"> <span class="username">@{{ username }}</span> - <span :class="$style.mainHost">@{{ toUnicode(host) }}</span> + <span class="host">@{{ toUnicode(host) }}</span> </span> </a> </template> @@ -41,8 +41,8 @@ const bgCss = bg.toRgbString(); useCssModule(); </script> -<style lang="scss" module> -.root { +<style lang="scss" scoped> +.akbvjaqn { display: inline-block; padding: 4px 8px 4px 4px; border-radius: 999px; @@ -51,18 +51,18 @@ useCssModule(); &.isMe { color: var(--mentionMe); } -} -.icon { - width: 1.5em; - height: 1.5em; - object-fit: cover; - margin: 0 0.2em 0 0; - vertical-align: bottom; - border-radius: 100%; -} + > .icon { + width: 1.5em; + height: 1.5em; + object-fit: cover; + margin: 0 0.2em 0 0; + vertical-align: bottom; + border-radius: 100%; + } -.mainHost { - opacity: 0.5; + > .main > .host { + opacity: 0.5; + } } </style> diff --git a/packages/client/src/components/mfm.ts b/packages/client/src/components/mfm.ts index f7dbca0d30..16ae45bfe1 100644 --- a/packages/client/src/components/mfm.ts +++ b/packages/client/src/components/mfm.ts @@ -47,7 +47,7 @@ export default defineComponent({ render() { if (this.text == null || this.text === '') return; - const ast = (this.plain ? mfm.parsePlain : mfm.parse)(this.text, { fnNameList: MFM_TAGS }); + const ast = (this.plain ? mfm.parseSimple : mfm.parse)(this.text, { fnNameList: MFM_TAGS }); const validTime = (t: string | null | undefined) => { if (t == null) return null; @@ -312,6 +312,10 @@ export default defineComponent({ })]; } + case 'plain': { + return [h('span', genEl(token.children))]; + } + default: { console.error('unrecognized ast type:', token.type); diff --git a/packages/client/src/components/note-preview.vue b/packages/client/src/components/note-preview.vue index be7214db19..a78b499654 100644 --- a/packages/client/src/components/note-preview.vue +++ b/packages/client/src/components/note-preview.vue @@ -27,7 +27,7 @@ const props = defineProps<{ display: flex; margin: 0; padding: 0; - overflow: hidden; overflow: clip; + overflow: clip; font-size: 0.95em; &.min-width_350px { diff --git a/packages/client/src/components/note-simple.vue b/packages/client/src/components/note-simple.vue index 93c34b6bf4..b813b9a2b9 100644 --- a/packages/client/src/components/note-simple.vue +++ b/packages/client/src/components/note-simple.vue @@ -36,7 +36,7 @@ const showContent = $ref(false); display: flex; margin: 0; padding: 0; - overflow: hidden; overflow: clip; + overflow: clip; font-size: 0.95em; &.min-width_350px { diff --git a/packages/client/src/components/note.vue b/packages/client/src/components/note.vue index b494c70392..c96cdddef2 100644 --- a/packages/client/src/components/note.vue +++ b/packages/client/src/components/note.vue @@ -293,7 +293,7 @@ function readPromo() { position: relative; transition: box-shadow 0.1s ease; font-size: 1.05em; - overflow: hidden; overflow: clip; + overflow: clip; contain: content; // これらの指定はパフォーマンス向上には有効だが、ノートの高さは一定でないため、 diff --git a/packages/client/src/components/tag-cloud.vue b/packages/client/src/components/tag-cloud.vue index 9f3bc1c603..bbebff497f 100644 --- a/packages/client/src/components/tag-cloud.vue +++ b/packages/client/src/components/tag-cloud.vue @@ -71,7 +71,7 @@ defineExpose({ <style lang="scss" scoped> .meijqfqm { position: relative; - overflow: hidden; overflow: clip; + overflow: clip; display: grid; place-items: center; diff --git a/packages/client/src/components/toast.vue b/packages/client/src/components/toast.vue index e0230dccd4..c9fad64eb6 100644 --- a/packages/client/src/components/toast.vue +++ b/packages/client/src/components/toast.vue @@ -54,7 +54,7 @@ onMounted(() => { width: min-content; box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3); border-radius: 8px; - overflow: hidden; overflow: clip; + overflow: clip; text-align: center; pointer-events: none; diff --git a/packages/client/src/components/ui/button.vue b/packages/client/src/components/ui/button.vue index d8052b511c..e6b20d9881 100644 --- a/packages/client/src/components/ui/button.vue +++ b/packages/client/src/components/ui/button.vue @@ -148,7 +148,7 @@ export default defineComponent({ text-decoration: none; background: var(--buttonBg); border-radius: 5px; - overflow: hidden; overflow: clip; + overflow: clip; box-sizing: border-box; transition: background 0.1s ease; diff --git a/packages/client/src/components/ui/container.vue b/packages/client/src/components/ui/container.vue index 784414e791..4be59adc2a 100644 --- a/packages/client/src/components/ui/container.vue +++ b/packages/client/src/components/ui/container.vue @@ -143,7 +143,7 @@ export default defineComponent({ .ukygtjoj { position: relative; - overflow: hidden; overflow: clip; + overflow: clip; contain: content; &.naked { diff --git a/packages/client/src/components/ui/modal.vue b/packages/client/src/components/ui/modal.vue index 385f6cdb2b..2305a02794 100644 --- a/packages/client/src/components/ui/modal.vue +++ b/packages/client/src/components/ui/modal.vue @@ -10,7 +10,7 @@ </template> <script lang="ts" setup> -import { nextTick, onMounted, computed, ref, watch, provide } from 'vue'; +import { nextTick, onMounted, watch, provide } from 'vue'; import * as os from '@/os'; import { isTouchUsing } from '@/scripts/touch'; import { defaultStore } from '@/store'; @@ -57,13 +57,13 @@ const emit = defineEmits<{ provide('modal', true); -const maxHeight = ref<number>(); -const fixed = ref(false); -const transformOrigin = ref('center'); -const showing = ref(true); -const content = ref<HTMLElement>(); +let maxHeight = $ref<number>(); +let fixed = $ref(false); +let transformOrigin = $ref('center'); +let showing = $ref(true); +let content = $ref<HTMLElement>(); const zIndex = os.claimZIndex(props.zPriority); -const type = computed(() => { +const type = $computed(() => { if (props.preferType === 'auto') { if (!defaultStore.state.disableDrawer && isTouchUsing && deviceKind === 'smartphone') { return 'drawer'; @@ -80,7 +80,7 @@ let contentClicking = false; const close = () => { // eslint-disable-next-line vue/no-mutating-props if (props.src) props.src.style.pointerEvents = 'auto'; - showing.value = false; + showing = false; emit('close'); }; @@ -89,8 +89,8 @@ const onBgClick = () => { emit('click'); }; -if (type.value === 'drawer') { - maxHeight.value = window.innerHeight / 1.5; +if (type === 'drawer') { + maxHeight = window.innerHeight / 1.5; } const keymap = { @@ -101,22 +101,21 @@ const MARGIN = 16; const align = () => { if (props.src == null) return; - if (type.value === 'drawer') return; - if (type.value === 'dialog') return; + if (type === 'drawer') return; + if (type === 'dialog') return; - const popover = content.value!; - if (popover == null) return; + if (content == null) return; const srcRect = props.src.getBoundingClientRect(); - - const width = popover.offsetWidth; - const height = popover.offsetHeight; + + const width = content!.offsetWidth; + const height = content!.offsetHeight; let left; let top; - const x = srcRect.left + (fixed.value ? 0 : window.pageXOffset); - const y = srcRect.top + (fixed.value ? 0 : window.pageYOffset); + const x = srcRect.left + (fixed ? 0 : window.pageXOffset); + const y = srcRect.top + (fixed ? 0 : window.pageYOffset); if (props.anchor.x === 'center') { left = x + (props.src.offsetWidth / 2) - (width / 2); @@ -134,7 +133,7 @@ const align = () => { top = y + props.src.offsetHeight; } - if (fixed.value) { + if (fixed) { // 画面から横にはみ出る場合 if (left + width > window.innerWidth) { left = window.innerWidth - width; @@ -147,16 +146,16 @@ const align = () => { if (top + height > (window.innerHeight - MARGIN)) { if (props.noOverlap && props.anchor.x === 'center') { if (underSpace >= (upperSpace / 3)) { - maxHeight.value = underSpace; + maxHeight = underSpace; } else { - maxHeight.value = upperSpace; + maxHeight = upperSpace; top = (upperSpace + MARGIN) - height; } } else { top = (window.innerHeight - MARGIN) - height; } } else { - maxHeight.value = underSpace; + maxHeight = underSpace; } } else { // 画面から横にはみ出る場合 @@ -171,16 +170,16 @@ const align = () => { if (top + height - window.pageYOffset > (window.innerHeight - MARGIN)) { if (props.noOverlap && props.anchor.x === 'center') { if (underSpace >= (upperSpace / 3)) { - maxHeight.value = underSpace; + maxHeight = underSpace; } else { - maxHeight.value = upperSpace; + maxHeight = upperSpace; top = window.pageYOffset + ((upperSpace + MARGIN) - height); } } else { top = (window.innerHeight - MARGIN) - height + window.pageYOffset - 1; } } else { - maxHeight.value = underSpace; + maxHeight = underSpace; } } @@ -195,29 +194,29 @@ const align = () => { let transformOriginX = 'center'; let transformOriginY = 'center'; - if (top >= srcRect.top + props.src.offsetHeight + (fixed.value ? 0 : window.pageYOffset)) { + if (top >= srcRect.top + props.src.offsetHeight + (fixed ? 0 : window.pageYOffset)) { transformOriginY = 'top'; - } else if ((top + height) <= srcRect.top + (fixed.value ? 0 : window.pageYOffset)) { + } else if ((top + height) <= srcRect.top + (fixed ? 0 : window.pageYOffset)) { transformOriginY = 'bottom'; } - if (left >= srcRect.left + props.src.offsetWidth + (fixed.value ? 0 : window.pageXOffset)) { + if (left >= srcRect.left + props.src.offsetWidth + (fixed ? 0 : window.pageXOffset)) { transformOriginX = 'left'; - } else if ((left + width) <= srcRect.left + (fixed.value ? 0 : window.pageXOffset)) { + } else if ((left + width) <= srcRect.left + (fixed ? 0 : window.pageXOffset)) { transformOriginX = 'right'; } - transformOrigin.value = `${transformOriginX} ${transformOriginY}`; + transformOrigin = `${transformOriginX} ${transformOriginY}`; - popover.style.left = left + 'px'; - popover.style.top = top + 'px'; + content.style.left = left + 'px'; + content.style.top = top + 'px'; }; const onOpened = () => { emit('opened'); // モーダルコンテンツにマウスボタンが押され、コンテンツ外でマウスボタンが離されたときにモーダルバックグラウンドクリックと判定させないためにマウスイベントを監視しフラグ管理する - const el = content.value!.children[0]; + const el = content!.children[0]; el.addEventListener('mousedown', ev => { contentClicking = true; window.addEventListener('mouseup', ev => { @@ -235,7 +234,7 @@ onMounted(() => { // eslint-disable-next-line vue/no-mutating-props props.src.style.pointerEvents = 'none'; } - fixed.value = (type.value === 'drawer') || (getFixedContainer(props.src) != null); + fixed = (type === 'drawer') || (getFixedContainer(props.src) != null); await nextTick(); @@ -243,10 +242,9 @@ onMounted(() => { }, { immediate: true }); nextTick(() => { - const popover = content.value; new ResizeObserver((entries, observer) => { align(); - }).observe(popover!); + }).observe(content!); }); }); @@ -389,7 +387,7 @@ defineExpose({ left: 0; width: 100%; height: 100%; - overflow: hidden; overflow: clip; + overflow: clip; > .content { position: fixed; diff --git a/packages/client/src/components/ui/super-menu.vue b/packages/client/src/components/ui/super-menu.vue index 78f524036d..8ce2dc5dc2 100644 --- a/packages/client/src/components/ui/super-menu.vue +++ b/packages/client/src/components/ui/super-menu.vue @@ -30,7 +30,7 @@ export default defineComponent({ props: { def: { type: Array, - required: true + required: true, }, grid: { type: Boolean, @@ -64,7 +64,7 @@ export default defineComponent({ box-sizing: border-box; padding: 10px 16px 10px 8px; border-radius: 9px; - font-size: 0.95em; + font-size: 0.9em; &:hover { text-decoration: none; diff --git a/packages/client/src/components/visibility-picker.vue b/packages/client/src/components/visibility-picker.vue index c717c3a461..7fe55858cc 100644 --- a/packages/client/src/components/visibility-picker.vue +++ b/packages/client/src/components/visibility-picker.vue @@ -105,7 +105,7 @@ function choose(visibility: typeof misskey.noteVisibilities[number]): void { } &.active { - color: #fff; + color: var(--fgOnAccent); background: var(--accent); } diff --git a/packages/client/src/components/widgets.vue b/packages/client/src/components/widgets.vue index 85b8ae0ed3..0a9769e197 100644 --- a/packages/client/src/components/widgets.vue +++ b/packages/client/src/components/widgets.vue @@ -4,7 +4,7 @@ <header> <MkSelect v-model="widgetAdderSelected" style="margin-bottom: var(--margin)" class="mk-widget-select"> <template #label>{{ $ts.selectWidget }}</template> - <option v-for="widget in widgetDefs" :key="widget" :value="widget">{{ $t(`_widgets.${widget}`) }}</option> + <option v-for="widget in widgetDefs" :key="widget" :value="widget">{{ i18n.t(`_widgets.${widget}`) }}</option> </MkSelect> <MkButton inline primary class="mk-widget-add" @click="addWidget"><i class="fas fa-plus"></i> {{ $ts.add }}</MkButton> <MkButton inline @click="$emit('exit')">{{ $ts.close }}</MkButton> @@ -26,79 +26,91 @@ </template> </XDraggable> </template> - <component :is="`mkw-${widget.name}`" v-for="widget in widgets" v-else :key="widget.id" class="widget" :widget="widget" @updateProps="updateWidget(widget.id, $event)"/> + <component :is="`mkw-${widget.name}`" v-for="widget in widgets" v-else :key="widget.id" :ref="el => widgetRefs[widget.id] = el" class="widget" :widget="widget" @updateProps="updateWidget(widget.id, $event)" @contextmenu.stop="onContextmenu(widget, $event)"/> </div> </template> -<script lang="ts"> -import { defineComponent, defineAsyncComponent, reactive, ref, computed } from 'vue'; +<script lang="ts" setup> +import { defineAsyncComponent, reactive, ref, computed } from 'vue'; import { v4 as uuid } from 'uuid'; import MkSelect from '@/components/form/select.vue'; import MkButton from '@/components/ui/button.vue'; import { widgets as widgetDefs } from '@/widgets'; +import * as os from '@/os'; +import { i18n } from '@/i18n'; -export default defineComponent({ - components: { - XDraggable: defineAsyncComponent(() => import('vuedraggable')), - MkSelect, - MkButton, - }, +const XDraggable = defineAsyncComponent(() => import('vuedraggable')); - props: { - widgets: { - type: Array, - required: true, - }, - edit: { - type: Boolean, - required: true, - }, - }, +type Widget = { + name: string; + id: string; + data: Record<string, any>; +}; - emits: ['updateWidgets', 'addWidget', 'removeWidget', 'updateWidget', 'exit'], +const props = defineProps<{ + widgets: Widget[]; + edit: boolean; +}>(); - setup(props, context) { - const widgetRefs = reactive({}); - const configWidget = (id: string) => { - widgetRefs[id].configure(); - }; - const widgetAdderSelected = ref(null); - const addWidget = () => { - if (widgetAdderSelected.value == null) return; +const emit = defineEmits<{ + (ev: 'updateWidgets', widgets: Widget[]): void; + (ev: 'addWidget', widget: Widget): void; + (ev: 'removeWidget', widget: Widget): void; + (ev: 'updateWidget', widget: Partial<Widget>): void; + (ev: 'exit'): void; +}>(); - context.emit('addWidget', { - name: widgetAdderSelected.value, - id: uuid(), - data: {}, - }); +const widgetRefs = {}; +const configWidget = (id: string) => { + widgetRefs[id].configure(); +}; +const widgetAdderSelected = ref(null); +const addWidget = () => { + if (widgetAdderSelected.value == null) return; - widgetAdderSelected.value = null; - }; - const removeWidget = (widget) => { - context.emit('removeWidget', widget); - }; - const updateWidget = (id, data) => { - context.emit('updateWidget', { id, data }); - }; - const widgets_ = computed({ - get: () => props.widgets, - set: (value) => { - context.emit('updateWidgets', value); - }, - }); + emit('addWidget', { + name: widgetAdderSelected.value, + id: uuid(), + data: {}, + }); - return { - widgetRefs, - configWidget, - widgetAdderSelected, - widgetDefs, - addWidget, - removeWidget, - updateWidget, - widgets_, - }; + widgetAdderSelected.value = null; +}; +const removeWidget = (widget) => { + emit('removeWidget', widget); +}; +const updateWidget = (id, data) => { + emit('updateWidget', { id, data }); +}; +const widgets_ = computed({ + get: () => props.widgets, + set: (value) => { + emit('updateWidgets', value); }, }); + +function onContextmenu(widget: Widget, ev: MouseEvent) { + const isLink = (el: HTMLElement) => { + if (el.tagName === 'A') return true; + if (el.parentElement) { + return isLink(el.parentElement); + } + }; + if (isLink(ev.target)) return; + if (['INPUT', 'TEXTAREA', 'IMG', 'VIDEO', 'CANVAS'].includes(ev.target.tagName) || ev.target.attributes['contenteditable']) return; + if (window.getSelection()?.toString() !== '') return; + + os.contextMenu([{ + type: 'label', + text: i18n.t(`_widgets.${widget.name}`), + }, { + icon: 'fas fa-cog', + text: i18n.ts.settings, + action: () => { + configWidget(widget.id); + }, + }], ev); +} </script> <style lang="scss" scoped> diff --git a/packages/client/src/directives/size.ts b/packages/client/src/directives/size.ts index 51855e0de5..c472a528ac 100644 --- a/packages/client/src/directives/size.ts +++ b/packages/client/src/directives/size.ts @@ -27,8 +27,8 @@ function getClassOrder(width: number, queue: Value): ClassOrder { ...(queue.min ? queue.min.filter(v => width >= v).map(getMinClass) : []), ], remove: [ - ...(queue.max ? queue.max.filter(v => width > v).map(getMaxClass) : []), - ...(queue.min ? queue.min.filter(v => width < v).map(getMinClass) : []), + ...(queue.max ? queue.max.filter(v => width > v).map(getMaxClass) : []), + ...(queue.min ? queue.min.filter(v => width < v).map(getMinClass) : []), ] }; } diff --git a/packages/client/src/init.ts b/packages/client/src/init.ts index 98f69c701f..94e7f9f6b3 100644 --- a/packages/client/src/init.ts +++ b/packages/client/src/init.ts @@ -39,401 +39,403 @@ import { reactionPicker } from '@/scripts/reaction-picker'; import { getUrlWithoutLoginId } from '@/scripts/login-id'; import { getAccountFromId } from '@/scripts/get-account-from-id'; -console.info(`Misskey v${version}`); +(async () => { + console.info(`Misskey v${version}`); -if (_DEV_) { - console.warn('Development mode!!!'); + if (_DEV_) { + console.warn('Development mode!!!'); - console.info(`vue ${vueVersion}`); + console.info(`vue ${vueVersion}`); - (window as any).$i = $i; - (window as any).$store = defaultStore; + (window as any).$i = $i; + (window as any).$store = defaultStore; - window.addEventListener('error', event => { - console.error(event); - /* - alert({ - type: 'error', - title: 'DEV: Unhandled error', - text: event.message + window.addEventListener('error', event => { + console.error(event); + /* + alert({ + type: 'error', + title: 'DEV: Unhandled error', + text: event.message + }); + */ }); - */ - }); - window.addEventListener('unhandledrejection', event => { - console.error(event); - /* - alert({ - type: 'error', - title: 'DEV: Unhandled promise rejection', - text: event.reason + window.addEventListener('unhandledrejection', event => { + console.error(event); + /* + alert({ + type: 'error', + title: 'DEV: Unhandled promise rejection', + text: event.reason + }); + */ }); - */ - }); -} + } -// タッチデバイスでCSSの:hoverを機能させる -document.addEventListener('touchend', () => {}, { passive: true }); + // タッチデバイスでCSSの:hoverを機能させる + document.addEventListener('touchend', () => {}, { passive: true }); -// 一斉リロード -reloadChannel.addEventListener('message', path => { - if (path !== null) location.href = path; - else location.reload(); -}); + // 一斉リロード + reloadChannel.addEventListener('message', path => { + if (path !== null) location.href = path; + else location.reload(); + }); -//#region SEE: https://css-tricks.com/the-trick-to-viewport-units-on-mobile/ -// TODO: いつの日にか消したい -const vh = window.innerHeight * 0.01; -document.documentElement.style.setProperty('--vh', `${vh}px`); -window.addEventListener('resize', () => { + //#region SEE: https://css-tricks.com/the-trick-to-viewport-units-on-mobile/ + // TODO: いつの日にか消したい const vh = window.innerHeight * 0.01; document.documentElement.style.setProperty('--vh', `${vh}px`); -}); -//#endregion + window.addEventListener('resize', () => { + const vh = window.innerHeight * 0.01; + document.documentElement.style.setProperty('--vh', `${vh}px`); + }); + //#endregion -// If mobile, insert the viewport meta tag -if (['smartphone', 'tablet'].includes(deviceKind)) { - const viewport = document.getElementsByName('viewport').item(0); - viewport.setAttribute('content', - `${viewport.getAttribute('content')}, minimum-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover`); -} + // If mobile, insert the viewport meta tag + if (['smartphone', 'tablet'].includes(deviceKind)) { + const viewport = document.getElementsByName('viewport').item(0); + viewport.setAttribute('content', + `${viewport.getAttribute('content')}, minimum-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover`); + } -//#region Set lang attr -const html = document.documentElement; -html.setAttribute('lang', lang); -//#endregion + //#region Set lang attr + const html = document.documentElement; + html.setAttribute('lang', lang); + //#endregion -//#region loginId -const params = new URLSearchParams(location.search); -const loginId = params.get('loginId'); + //#region loginId + const params = new URLSearchParams(location.search); + const loginId = params.get('loginId'); -if (loginId) { - const target = getUrlWithoutLoginId(location.href); + if (loginId) { + const target = getUrlWithoutLoginId(location.href); - if (!$i || $i.id !== loginId) { - const account = await getAccountFromId(loginId); - if (account) { - await login(account.token, target); + if (!$i || $i.id !== loginId) { + const account = await getAccountFromId(loginId); + if (account) { + await login(account.token, target); + } } - } - - history.replaceState({ misskey: 'loginId' }, '', target); -} - -//#endregion -//#region Fetch user -if ($i && $i.token) { - if (_DEV_) { - console.log('account cache found. refreshing...'); - } - - refreshAccount(); -} else { - if (_DEV_) { - console.log('no account cache found.'); + history.replaceState({ misskey: 'loginId' }, '', target); } - // 連携ログインの場合用にCookieを参照する - const i = (document.cookie.match(/igi=(\w+)/) || [null, null])[1]; + //#endregion - if (i != null && i !== 'null') { + //#region Fetch user + if ($i && $i.token) { if (_DEV_) { - console.log('signing...'); + console.log('account cache found. refreshing...'); } - try { - document.body.innerHTML = '<div>Please wait...</div>'; - await login(i); - } catch (err) { - // Render the error screen - // TODO: ちゃんとしたコンポーネントをレンダリングする(v10とかのトラブルシューティングゲーム付きのやつみたいな) - document.body.innerHTML = '<div id="err">Oops!</div>'; - } + refreshAccount(); } else { if (_DEV_) { - console.log('not signed in'); + console.log('no account cache found.'); + } + + // 連携ログインの場合用にCookieを参照する + const i = (document.cookie.match(/igi=(\w+)/) || [null, null])[1]; + + if (i != null && i !== 'null') { + if (_DEV_) { + console.log('signing...'); + } + + try { + document.body.innerHTML = '<div>Please wait...</div>'; + await login(i); + } catch (err) { + // Render the error screen + // TODO: ちゃんとしたコンポーネントをレンダリングする(v10とかのトラブルシューティングゲーム付きのやつみたいな) + document.body.innerHTML = '<div id="err">Oops!</div>'; + } + } else { + if (_DEV_) { + console.log('not signed in'); + } } } -} -//#endregion + //#endregion -const fetchInstanceMetaPromise = fetchInstance(); + const fetchInstanceMetaPromise = fetchInstance(); -fetchInstanceMetaPromise.then(() => { - localStorage.setItem('v', instance.version); + fetchInstanceMetaPromise.then(() => { + localStorage.setItem('v', instance.version); - // Init service worker - initializeSw(); -}); + // Init service worker + initializeSw(); + }); -const app = createApp( - window.location.search === '?zen' ? defineAsyncComponent(() => import('@/ui/zen.vue')) : - !$i ? defineAsyncComponent(() => import('@/ui/visitor.vue')) : - ui === 'deck' ? defineAsyncComponent(() => import('@/ui/deck.vue')) : - ui === 'classic' ? defineAsyncComponent(() => import('@/ui/classic.vue')) : - defineAsyncComponent(() => import('@/ui/universal.vue')), -); + const app = createApp( + window.location.search === '?zen' ? defineAsyncComponent(() => import('@/ui/zen.vue')) : + !$i ? defineAsyncComponent(() => import('@/ui/visitor.vue')) : + ui === 'deck' ? defineAsyncComponent(() => import('@/ui/deck.vue')) : + ui === 'classic' ? defineAsyncComponent(() => import('@/ui/classic.vue')) : + defineAsyncComponent(() => import('@/ui/universal.vue')), + ); -if (_DEV_) { - app.config.performance = true; -} + if (_DEV_) { + app.config.performance = true; + } -app.config.globalProperties = { - $i, - $store: defaultStore, - $instance: instance, - $t: i18n.t, - $ts: i18n.ts, -}; + app.config.globalProperties = { + $i, + $store: defaultStore, + $instance: instance, + $t: i18n.t, + $ts: i18n.ts, + }; -widgets(app); -directives(app); -components(app); + widgets(app); + directives(app); + components(app); -const splash = document.getElementById('splash'); -// 念のためnullチェック(HTMLが古い場合があるため(そのうち消す)) -if (splash) splash.addEventListener('transitionend', () => { - splash.remove(); -}); + const splash = document.getElementById('splash'); + // 念のためnullチェック(HTMLが古い場合があるため(そのうち消す)) + if (splash) splash.addEventListener('transitionend', () => { + splash.remove(); + }); -// https://github.com/misskey-dev/misskey/pull/8575#issuecomment-1114239210 -// なぜかinit.tsの内容が2回実行されることがあるため、mountするdivを1つに制限する -const rootEl = (() => { - const MISSKEY_MOUNT_DIV_ID = 'misskey_app'; + // https://github.com/misskey-dev/misskey/pull/8575#issuecomment-1114239210 + // なぜかinit.tsの内容が2回実行されることがあるため、mountするdivを1つに制限する + const rootEl = (() => { + const MISSKEY_MOUNT_DIV_ID = 'misskey_app'; - const currentEl = document.getElementById(MISSKEY_MOUNT_DIV_ID); + const currentEl = document.getElementById(MISSKEY_MOUNT_DIV_ID); - if (currentEl) { - console.warn('multiple import detected'); - return currentEl; - } + if (currentEl) { + console.warn('multiple import detected'); + return currentEl; + } - const rootEl = document.createElement('div'); - rootEl.id = MISSKEY_MOUNT_DIV_ID; - document.body.appendChild(rootEl); - return rootEl; -})(); + const rootEl = document.createElement('div'); + rootEl.id = MISSKEY_MOUNT_DIV_ID; + document.body.appendChild(rootEl); + return rootEl; + })(); -app.mount(rootEl); + app.mount(rootEl); -// boot.jsのやつを解除 -window.onerror = null; -window.onunhandledrejection = null; + // boot.jsのやつを解除 + window.onerror = null; + window.onunhandledrejection = null; -reactionPicker.init(); + reactionPicker.init(); -if (splash) { - splash.style.opacity = '0'; - splash.style.pointerEvents = 'none'; -} + if (splash) { + splash.style.opacity = '0'; + splash.style.pointerEvents = 'none'; + } -// クライアントが更新されたか? -const lastVersion = localStorage.getItem('lastVersion'); -if (lastVersion !== version) { - localStorage.setItem('lastVersion', version); + // クライアントが更新されたか? + const lastVersion = localStorage.getItem('lastVersion'); + if (lastVersion !== version) { + localStorage.setItem('lastVersion', version); - // テーマリビルドするため - localStorage.removeItem('theme'); + // テーマリビルドするため + localStorage.removeItem('theme'); - try { // 変なバージョン文字列来るとcompareVersionsでエラーになるため - if (lastVersion != null && compareVersions(version, lastVersion) === 1) { - // ログインしてる場合だけ - if ($i) { - popup(defineAsyncComponent(() => import('@/components/updated.vue')), {}, {}, 'closed'); + try { // 変なバージョン文字列来るとcompareVersionsでエラーになるため + if (lastVersion != null && compareVersions(version, lastVersion) === 1) { + // ログインしてる場合だけ + if ($i) { + popup(defineAsyncComponent(() => import('@/components/updated.vue')), {}, {}, 'closed'); + } } + } catch (err) { } - } catch (err) { } -} -// NOTE: この処理は必ず↑のクライアント更新時処理より後に来ること(テーマ再構築のため) -watch(defaultStore.reactiveState.darkMode, (darkMode) => { - applyTheme(darkMode ? ColdDeviceStorage.get('darkTheme') : ColdDeviceStorage.get('lightTheme')); -}, { immediate: localStorage.theme == null }); + // NOTE: この処理は必ず↑のクライアント更新時処理より後に来ること(テーマ再構築のため) + watch(defaultStore.reactiveState.darkMode, (darkMode) => { + applyTheme(darkMode ? ColdDeviceStorage.get('darkTheme') : ColdDeviceStorage.get('lightTheme')); + }, { immediate: localStorage.theme == null }); -const darkTheme = computed(ColdDeviceStorage.makeGetterSetter('darkTheme')); -const lightTheme = computed(ColdDeviceStorage.makeGetterSetter('lightTheme')); - -watch(darkTheme, (theme) => { - if (defaultStore.state.darkMode) { - applyTheme(theme); - } -}); + const darkTheme = computed(ColdDeviceStorage.makeGetterSetter('darkTheme')); + const lightTheme = computed(ColdDeviceStorage.makeGetterSetter('lightTheme')); -watch(lightTheme, (theme) => { - if (!defaultStore.state.darkMode) { - applyTheme(theme); - } -}); + watch(darkTheme, (theme) => { + if (defaultStore.state.darkMode) { + applyTheme(theme); + } + }); -//#region Sync dark mode -if (ColdDeviceStorage.get('syncDeviceDarkMode')) { - defaultStore.set('darkMode', isDeviceDarkmode()); -} + watch(lightTheme, (theme) => { + if (!defaultStore.state.darkMode) { + applyTheme(theme); + } + }); -window.matchMedia('(prefers-color-scheme: dark)').addListener(mql => { + //#region Sync dark mode if (ColdDeviceStorage.get('syncDeviceDarkMode')) { - defaultStore.set('darkMode', mql.matches); + defaultStore.set('darkMode', isDeviceDarkmode()); } -}); -//#endregion -fetchInstanceMetaPromise.then(() => { - if (defaultStore.state.themeInitial) { - if (instance.defaultLightTheme != null) ColdDeviceStorage.set('lightTheme', JSON5.parse(instance.defaultLightTheme)); - if (instance.defaultDarkTheme != null) ColdDeviceStorage.set('darkTheme', JSON5.parse(instance.defaultDarkTheme)); - defaultStore.set('themeInitial', false); - } -}); + window.matchMedia('(prefers-color-scheme: dark)').addListener(mql => { + if (ColdDeviceStorage.get('syncDeviceDarkMode')) { + defaultStore.set('darkMode', mql.matches); + } + }); + //#endregion -watch(defaultStore.reactiveState.useBlurEffectForModal, v => { - document.documentElement.style.setProperty('--modalBgFilter', v ? 'blur(4px)' : 'none'); -}, { immediate: true }); + fetchInstanceMetaPromise.then(() => { + if (defaultStore.state.themeInitial) { + if (instance.defaultLightTheme != null) ColdDeviceStorage.set('lightTheme', JSON5.parse(instance.defaultLightTheme)); + if (instance.defaultDarkTheme != null) ColdDeviceStorage.set('darkTheme', JSON5.parse(instance.defaultDarkTheme)); + defaultStore.set('themeInitial', false); + } + }); -watch(defaultStore.reactiveState.useBlurEffect, v => { - if (v) { - document.documentElement.style.removeProperty('--blur'); - } else { - document.documentElement.style.setProperty('--blur', 'none'); - } -}, { immediate: true }); + watch(defaultStore.reactiveState.useBlurEffectForModal, v => { + document.documentElement.style.setProperty('--modalBgFilter', v ? 'blur(4px)' : 'none'); + }, { immediate: true }); -let reloadDialogShowing = false; -stream.on('_disconnected_', async () => { - if (defaultStore.state.serverDisconnectedBehavior === 'reload') { - location.reload(); - } else if (defaultStore.state.serverDisconnectedBehavior === 'dialog') { - if (reloadDialogShowing) return; - reloadDialogShowing = true; - const { canceled } = await confirm({ - type: 'warning', - title: i18n.ts.disconnectedFromServer, - text: i18n.ts.reloadConfirm, - }); - reloadDialogShowing = false; - if (!canceled) { - location.reload(); + watch(defaultStore.reactiveState.useBlurEffect, v => { + if (v) { + document.documentElement.style.removeProperty('--blur'); + } else { + document.documentElement.style.setProperty('--blur', 'none'); } - } -}); + }, { immediate: true }); -stream.on('emojiAdded', emojiData => { - // TODO - //store.commit('instance/set', ); -}); - -for (const plugin of ColdDeviceStorage.get('plugins').filter(p => p.active)) { - import('./plugin').then(({ install }) => { - install(plugin); + let reloadDialogShowing = false; + stream.on('_disconnected_', async () => { + if (defaultStore.state.serverDisconnectedBehavior === 'reload') { + location.reload(); + } else if (defaultStore.state.serverDisconnectedBehavior === 'dialog') { + if (reloadDialogShowing) return; + reloadDialogShowing = true; + const { canceled } = await confirm({ + type: 'warning', + title: i18n.ts.disconnectedFromServer, + text: i18n.ts.reloadConfirm, + }); + reloadDialogShowing = false; + if (!canceled) { + location.reload(); + } + } }); -} - -const hotkeys = { - 'd': (): void => { - defaultStore.set('darkMode', !defaultStore.state.darkMode); - }, - 's': search, -}; -if ($i) { - // only add post shortcuts if logged in - hotkeys['p|n'] = post; + stream.on('emojiAdded', emojiData => { + // TODO + //store.commit('instance/set', ); + }); - if ($i.isDeleted) { - alert({ - type: 'warning', - text: i18n.ts.accountDeletionInProgress, + for (const plugin of ColdDeviceStorage.get('plugins').filter(p => p.active)) { + import('./plugin').then(({ install }) => { + install(plugin); }); } - const lastUsed = localStorage.getItem('lastUsed'); - if (lastUsed) { - const lastUsedDate = parseInt(lastUsed, 10); - // 二時間以上前なら - if (Date.now() - lastUsedDate > 1000 * 60 * 60 * 2) { - toast(i18n.t('welcomeBackWithName', { - name: $i.name || $i.username, - })); + const hotkeys = { + 'd': (): void => { + defaultStore.set('darkMode', !defaultStore.state.darkMode); + }, + 's': search, + }; + + if ($i) { + // only add post shortcuts if logged in + hotkeys['p|n'] = post; + + if ($i.isDeleted) { + alert({ + type: 'warning', + text: i18n.ts.accountDeletionInProgress, + }); } - } - localStorage.setItem('lastUsed', Date.now().toString()); - if ('Notification' in window) { - // 許可を得ていなかったらリクエスト - if (Notification.permission === 'default') { - Notification.requestPermission(); + const lastUsed = localStorage.getItem('lastUsed'); + if (lastUsed) { + const lastUsedDate = parseInt(lastUsed, 10); + // 二時間以上前なら + if (Date.now() - lastUsedDate > 1000 * 60 * 60 * 2) { + toast(i18n.t('welcomeBackWithName', { + name: $i.name || $i.username, + })); + } } - } + localStorage.setItem('lastUsed', Date.now().toString()); - const main = markRaw(stream.useChannel('main', null, 'System')); + if ('Notification' in window) { + // 許可を得ていなかったらリクエスト + if (Notification.permission === 'default') { + Notification.requestPermission(); + } + } - // 自分の情報が更新されたとき - main.on('meUpdated', i => { - updateAccount(i); - }); + const main = markRaw(stream.useChannel('main', null, 'System')); - main.on('readAllNotifications', () => { - updateAccount({ hasUnreadNotification: false }); - }); + // 自分の情報が更新されたとき + main.on('meUpdated', i => { + updateAccount(i); + }); - main.on('unreadNotification', () => { - updateAccount({ hasUnreadNotification: true }); - }); + main.on('readAllNotifications', () => { + updateAccount({ hasUnreadNotification: false }); + }); - main.on('unreadMention', () => { - updateAccount({ hasUnreadMentions: true }); - }); + main.on('unreadNotification', () => { + updateAccount({ hasUnreadNotification: true }); + }); - main.on('readAllUnreadMentions', () => { - updateAccount({ hasUnreadMentions: false }); - }); + main.on('unreadMention', () => { + updateAccount({ hasUnreadMentions: true }); + }); - main.on('unreadSpecifiedNote', () => { - updateAccount({ hasUnreadSpecifiedNotes: true }); - }); + main.on('readAllUnreadMentions', () => { + updateAccount({ hasUnreadMentions: false }); + }); - main.on('readAllUnreadSpecifiedNotes', () => { - updateAccount({ hasUnreadSpecifiedNotes: false }); - }); + main.on('unreadSpecifiedNote', () => { + updateAccount({ hasUnreadSpecifiedNotes: true }); + }); - main.on('readAllMessagingMessages', () => { - updateAccount({ hasUnreadMessagingMessage: false }); - }); + main.on('readAllUnreadSpecifiedNotes', () => { + updateAccount({ hasUnreadSpecifiedNotes: false }); + }); - main.on('unreadMessagingMessage', () => { - updateAccount({ hasUnreadMessagingMessage: true }); - sound.play('chatBg'); - }); + main.on('readAllMessagingMessages', () => { + updateAccount({ hasUnreadMessagingMessage: false }); + }); - main.on('readAllAntennas', () => { - updateAccount({ hasUnreadAntenna: false }); - }); + main.on('unreadMessagingMessage', () => { + updateAccount({ hasUnreadMessagingMessage: true }); + sound.play('chatBg'); + }); - main.on('unreadAntenna', () => { - updateAccount({ hasUnreadAntenna: true }); - sound.play('antenna'); - }); + main.on('readAllAntennas', () => { + updateAccount({ hasUnreadAntenna: false }); + }); - main.on('readAllAnnouncements', () => { - updateAccount({ hasUnreadAnnouncement: false }); - }); + main.on('unreadAntenna', () => { + updateAccount({ hasUnreadAntenna: true }); + sound.play('antenna'); + }); - main.on('readAllChannels', () => { - updateAccount({ hasUnreadChannel: false }); - }); + main.on('readAllAnnouncements', () => { + updateAccount({ hasUnreadAnnouncement: false }); + }); - main.on('unreadChannel', () => { - updateAccount({ hasUnreadChannel: true }); - sound.play('channel'); - }); + main.on('readAllChannels', () => { + updateAccount({ hasUnreadChannel: false }); + }); - // トークンが再生成されたとき - // このままではMisskeyが利用できないので強制的にサインアウトさせる - main.on('myTokenRegenerated', () => { - signout(); - }); -} + main.on('unreadChannel', () => { + updateAccount({ hasUnreadChannel: true }); + sound.play('channel'); + }); + + // トークンが再生成されたとき + // このままではMisskeyが利用できないので強制的にサインアウトさせる + main.on('myTokenRegenerated', () => { + signout(); + }); + } -// shortcut -document.addEventListener('keydown', makeHotkey(hotkeys)); + // shortcut + document.addEventListener('keydown', makeHotkey(hotkeys)); +})(); diff --git a/packages/client/src/nirax.ts b/packages/client/src/nirax.ts index cd29ae87a5..4efa0345af 100644 --- a/packages/client/src/nirax.ts +++ b/packages/client/src/nirax.ts @@ -3,6 +3,7 @@ import { EventEmitter } from 'eventemitter3'; import { Ref, Component, ref, shallowRef, ShallowRef } from 'vue'; import { pleaseLogin } from '@/scripts/please-login'; +import { safeURIDecode } from '@/scripts/safe-uri-decode'; type RouteDef = { path: string; @@ -116,7 +117,7 @@ export class Router extends EventEmitter<{ } if (p.wildcard) { if (parts.length !== 0) { - props.set(p.name, parts.join('/')); + props.set(p.name, safeURIDecode(parts.join('/'))); parts = []; } break pathMatchLoop; @@ -124,10 +125,12 @@ export class Router extends EventEmitter<{ if (p.startsWith) { if (parts[0] == null || !parts[0].startsWith(p.startsWith)) continue forEachRouteLoop; - props.set(p.name, parts[0].substring(p.startsWith.length)); + props.set(p.name, safeURIDecode(parts[0].substring(p.startsWith.length))); parts.shift(); } else { - props.set(p.name, parts[0]); + if (parts[0]) { + props.set(p.name, safeURIDecode(parts[0])); + } parts.shift(); } } @@ -137,7 +140,7 @@ export class Router extends EventEmitter<{ if (parts.length !== 0) continue forEachRouteLoop; if (route.hash != null && hash != null) { - props.set(route.hash, hash); + props.set(route.hash, safeURIDecode(hash)); } if (route.query != null && queryString != null) { @@ -147,7 +150,7 @@ export class Router extends EventEmitter<{ for (const q in route.query) { const as = route.query[q]; if (queryObject[q]) { - props.set(as, queryObject[q]); + props.set(as, safeURIDecode(queryObject[q])); } } } diff --git a/packages/client/src/pages/about-misskey.vue b/packages/client/src/pages/about-misskey.vue index a80041b5ce..fd7b5f936d 100644 --- a/packages/client/src/pages/about-misskey.vue +++ b/packages/client/src/pages/about-misskey.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <div style="overflow: hidden; overflow: clip;"> + <div style="overflow: clip;"> <MkSpacer :content-max="600" :margin-min="20"> <div class="_formRoot znqjceqz"> <div id="debug"></div> diff --git a/packages/client/src/pages/about.vue b/packages/client/src/pages/about.vue index 6241bbbdda..e482c4ca6d 100644 --- a/packages/client/src/pages/about.vue +++ b/packages/client/src/pages/about.vue @@ -138,7 +138,7 @@ definePageMetadata(computed(() => ({ .fwhjspax { text-align: center; border-radius: 10px; - overflow: hidden; overflow: clip; + overflow: clip; background-size: cover; background-position: center center; diff --git a/packages/client/src/pages/admin/index.vue b/packages/client/src/pages/admin/index.vue index f0ac5b3fc9..d82880c34a 100644 --- a/packages/client/src/pages/admin/index.vue +++ b/packages/client/src/pages/admin/index.vue @@ -58,7 +58,7 @@ let view = $ref(null); let el = $ref(null); let pageProps = $ref({}); let noMaintainerInformation = isEmpty(instance.maintainerName) || isEmpty(instance.maintainerEmail); -let noBotProtection = !instance.enableHcaptcha && !instance.enableRecaptcha; +let noBotProtection = !instance.disableRegistration && !instance.enableHcaptcha && !instance.enableRecaptcha; let noEmailServer = !instance.enableEmail; let thereIsUnresolvedAbuseReport = $ref(false); diff --git a/packages/client/src/pages/admin/overview.vue b/packages/client/src/pages/admin/overview.vue index 7e085106b9..c186df15a7 100644 --- a/packages/client/src/pages/admin/overview.vue +++ b/packages/client/src/pages/admin/overview.vue @@ -355,7 +355,7 @@ async function renderChart() { plugins: [{ id: 'vLine', beforeDraw(chart, args, options) { - if (chart.tooltip._active && chart.tooltip._active.length) { + if (chart.tooltip?._active?.length) { const activePoint = chart.tooltip._active[0]; const ctx = chart.ctx; const x = activePoint.element.x; @@ -561,7 +561,7 @@ definePageMetadata({ > .body { background: var(--panel); border-radius: var(--radius); - overflow: hidden; overflow: clip; + overflow: clip; } } @@ -620,7 +620,7 @@ definePageMetadata({ > .body { background: var(--panel); border-radius: var(--radius); - overflow: hidden; overflow: clip; + overflow: clip; } } } diff --git a/packages/client/src/pages/antenna-timeline.vue b/packages/client/src/pages/antenna-timeline.vue index 309f94f9f5..1865781a0e 100644 --- a/packages/client/src/pages/antenna-timeline.vue +++ b/packages/client/src/pages/antenna-timeline.vue @@ -110,7 +110,7 @@ definePageMetadata(computed(() => antenna ? { > .tl { background: var(--bg); border-radius: var(--radius); - overflow: hidden; overflow: clip; + overflow: clip; } &.min-width_800px { diff --git a/packages/client/src/pages/explore.users.vue b/packages/client/src/pages/explore.users.vue index bdc96b33a3..8af37ab529 100644 --- a/packages/client/src/pages/explore.users.vue +++ b/packages/client/src/pages/explore.users.vue @@ -1,5 +1,9 @@ <template> <MkSpacer :content-max="1200"> + <MkTab v-model="origin" style="margin-bottom: var(--margin);"> + <option value="local">{{ $ts.local }}</option> + <option value="remote">{{ $ts.remote }}</option> + </MkTab> <div v-if="origin === 'local'"> <template v-if="tag == null"> <MkFolder class="_gap" persist-key="explore-pinned-users"> @@ -57,16 +61,17 @@ import { computed, watch } from 'vue'; import XUserList from '@/components/user-list.vue'; import MkFolder from '@/components/ui/folder.vue'; +import MkTab from '@/components/tab.vue'; import number from '@/filters/number'; import * as os from '@/os'; import { i18n } from '@/i18n'; import { instance } from '@/instance'; const props = defineProps<{ - origin: 'local' | 'remote'; tag?: string; }>(); +let origin = $ref('local'); let tagsEl = $ref<InstanceType<typeof MkFolder>>(); let tagsLocal = $ref([]); let tagsRemote = $ref([]); diff --git a/packages/client/src/pages/explore.vue b/packages/client/src/pages/explore.vue index c0b9438a50..059e94d1df 100644 --- a/packages/client/src/pages/explore.vue +++ b/packages/client/src/pages/explore.vue @@ -5,11 +5,8 @@ <div v-if="tab === 'featured'"> <XFeatured/> </div> - <div v-else-if="tab === 'localUsers'"> - <XUsers origin="local"/> - </div> - <div v-else-if="tab === 'remoteUsers'"> - <XUsers origin="remote"/> + <div v-else-if="tab === 'users'"> + <XUsers/> </div> <div v-else-if="tab === 'search'"> <MkSpacer :content-max="1200"> @@ -75,14 +72,10 @@ const headerTabs = $computed(() => [{ icon: 'fas fa-bolt', title: i18n.ts.featured, }, { - key: 'localUsers', + key: 'users', icon: 'fas fa-users', title: i18n.ts.users, }, { - key: 'remoteUsers', - icon: 'fas fa-users', - title: i18n.ts.remote, -}, { key: 'search', title: i18n.ts.search, }]); diff --git a/packages/client/src/pages/settings/profile.vue b/packages/client/src/pages/settings/profile.vue index 2a326fc2b6..121709f127 100644 --- a/packages/client/src/pages/settings/profile.vue +++ b/packages/client/src/pages/settings/profile.vue @@ -188,7 +188,7 @@ definePageMetadata({ background-size: cover; background-position: center; border-radius: 10px; - overflow: hidden; overflow: clip; + overflow: clip; > .avatar { display: inline-block; diff --git a/packages/client/src/pages/settings/theme.vue b/packages/client/src/pages/settings/theme.vue index d330e1ba25..667155019b 100644 --- a/packages/client/src/pages/settings/theme.vue +++ b/packages/client/src/pages/settings/theme.vue @@ -181,7 +181,7 @@ definePageMetadata({ > .toggleWrapper { display: inline-block; text-align: left; - overflow: hidden; overflow: clip; + overflow: clip; padding: 0 100px; input { diff --git a/packages/client/src/pages/timeline.vue b/packages/client/src/pages/timeline.vue index 8554a9aebc..40eb85ff43 100644 --- a/packages/client/src/pages/timeline.vue +++ b/packages/client/src/pages/timeline.vue @@ -177,7 +177,7 @@ definePageMetadata(computed(() => ({ > .tl { background: var(--bg); border-radius: var(--radius); - overflow: hidden; overflow: clip; + overflow: clip; } } </style> diff --git a/packages/client/src/pages/user-list-timeline.vue b/packages/client/src/pages/user-list-timeline.vue index 3fca6f1416..593db1dea7 100644 --- a/packages/client/src/pages/user-list-timeline.vue +++ b/packages/client/src/pages/user-list-timeline.vue @@ -103,7 +103,7 @@ definePageMetadata(computed(() => list ? { > .tl { background: var(--bg); border-radius: var(--radius); - overflow: hidden; overflow: clip; + overflow: clip; } &.min-width_800px { diff --git a/packages/client/src/pages/user/index.photos.vue b/packages/client/src/pages/user/index.photos.vue index cedb0e05f3..79dd1726e1 100644 --- a/packages/client/src/pages/user/index.photos.vue +++ b/packages/client/src/pages/user/index.photos.vue @@ -90,7 +90,7 @@ export default defineComponent({ > .img { height: 128px; border-radius: 6px; - overflow: hidden; overflow: clip; + overflow: clip; } } diff --git a/packages/client/src/pages/welcome.entrance.a.vue b/packages/client/src/pages/welcome.entrance.a.vue index f9d5852212..240177c9d9 100644 --- a/packages/client/src/pages/welcome.entrance.a.vue +++ b/packages/client/src/pages/welcome.entrance.a.vue @@ -276,7 +276,7 @@ function showMenu(ev) { -webkit-backdrop-filter: var(--blur, blur(15px)); backdrop-filter: var(--blur, blur(15px)); border-radius: 999px; - overflow: hidden; overflow: clip; + overflow: clip; width: 800px; padding: 8px 0; diff --git a/packages/client/src/scripts/emojilist.ts b/packages/client/src/scripts/emojilist.ts index 4196170d24..4ce63dc7e7 100644 --- a/packages/client/src/scripts/emojilist.ts +++ b/packages/client/src/scripts/emojilist.ts @@ -8,4 +8,6 @@ export type UnicodeEmojiDef = { } // initial converted from https://github.com/muan/emojilib/commit/242fe68be86ed6536843b83f7e32f376468b38fb -export const emojilist = (await import('../emojilist.json')).default as UnicodeEmojiDef[]; +import _emojilist from '../emojilist.json'; + +export const emojilist = _emojilist as UnicodeEmojiDef[]; diff --git a/packages/client/src/scripts/hpml/expr.ts b/packages/client/src/scripts/hpml/expr.ts index 00e3ed118b..18c7c2a14b 100644 --- a/packages/client/src/scripts/hpml/expr.ts +++ b/packages/client/src/scripts/hpml/expr.ts @@ -16,7 +16,7 @@ export type TextValue = ExprBase & { value: string; }; -export type MultiLineTextValue = ExprBase & { +export type MultiLineTextValue = ExprBase & { type: 'multiLineText'; value: string; }; diff --git a/packages/client/src/scripts/idb-proxy.ts b/packages/client/src/scripts/idb-proxy.ts index d462a0d7ce..77bb84463c 100644 --- a/packages/client/src/scripts/idb-proxy.ts +++ b/packages/client/src/scripts/idb-proxy.ts @@ -11,16 +11,15 @@ const fallbackName = (key: string) => `idbfallback::${key}`; let idbAvailable = typeof window !== 'undefined' ? !!window.indexedDB : true; if (idbAvailable) { - try { - await iset('idb-test', 'test'); - } catch (err) { + iset('idb-test', 'test').catch(err => { console.error('idb error', err); + console.error('indexedDB is unavailable. It will use localStorage.'); idbAvailable = false; - } + }); +} else { + console.error('indexedDB is unavailable. It will use localStorage.'); } -if (!idbAvailable) console.error('indexedDB is unavailable. It will use localStorage.'); - export async function get(key: string) { if (idbAvailable) return iget(key); return JSON.parse(localStorage.getItem(fallbackName(key))); diff --git a/packages/client/src/scripts/safe-uri-decode.ts b/packages/client/src/scripts/safe-uri-decode.ts new file mode 100644 index 0000000000..301b56d7fd --- /dev/null +++ b/packages/client/src/scripts/safe-uri-decode.ts @@ -0,0 +1,7 @@ +export function safeURIDecode(str: string): string { + try { + return decodeURIComponent(str); + } catch { + return str; + } +} diff --git a/packages/client/src/scripts/theme.ts b/packages/client/src/scripts/theme.ts index dec9fb355c..77d1df0826 100644 --- a/packages/client/src/scripts/theme.ts +++ b/packages/client/src/scripts/theme.ts @@ -1,6 +1,6 @@ import { ref } from 'vue'; -import { globalEvents } from '@/events'; import tinycolor from 'tinycolor2'; +import { globalEvents } from '@/events'; export type Theme = { id: string; @@ -31,11 +31,11 @@ export const getBuiltinThemes = () => Promise.all( 'd-astro', 'd-future', 'd-botanical', + 'd-green-lime', + 'd-green-orange', 'd-cherry', 'd-ice', - 'd-pumpkin', - 'd-black', - ].map(name => import(`../themes/${name}.json5`).then(({ default: _default }): Theme => _default)) + ].map(name => import(`../themes/${name}.json5`).then(({ default: _default }): Theme => _default)), ); export const getBuiltinThemesRef = () => { diff --git a/packages/client/src/style.scss b/packages/client/src/style.scss index 9b30e64a31..0f892d2e19 100644 --- a/packages/client/src/style.scss +++ b/packages/client/src/style.scss @@ -252,7 +252,7 @@ hr { ._panel { background: var(--panel); border-radius: var(--radius); - overflow: hidden; overflow: clip; + overflow: clip; } ._block { diff --git a/packages/client/src/themes/d-black.json5 b/packages/client/src/themes/d-black.json5 deleted file mode 100644 index 3c18ebdaf1..0000000000 --- a/packages/client/src/themes/d-black.json5 +++ /dev/null @@ -1,17 +0,0 @@ -{ - id: '8c539dc1-0fab-4d47-9194-39c508e9bfe1', - - name: 'Mi Black', - author: 'syuilo', - - base: 'dark', - - props: { - divider: '#2d2d2d', - panel: '#131313', - panelHeaderBg: '@panel', - panelHeaderDivider: '@divider', - shadow: 'rgba(255, 255, 255, 0.05)', - modalBg: 'rgba(255, 255, 255, 0.1)', - }, -} diff --git a/packages/client/src/themes/d-green-lime.json5 b/packages/client/src/themes/d-green-lime.json5 new file mode 100644 index 0000000000..a6983b9ac2 --- /dev/null +++ b/packages/client/src/themes/d-green-lime.json5 @@ -0,0 +1,24 @@ +{ + id: '02816013-8107-440f-877e-865083ffe194', + + name: 'Mi Green+Lime Dark', + author: 'syuilo', + + base: 'dark', + + props: { + accent: '#b4e900', + bg: '#0C1210', + fg: '#dee7e4', + fgHighlighted: '#fff', + fgOnAccent: '#192320', + divider: '#e7fffb24', + panel: '#192320', + panelHeaderBg: '@panel', + panelHeaderDivider: '@divider', + popup: '#293330', + renote: '@accent', + mentionMe: '#ffaa00', + link: '#24d7ce', + }, +} diff --git a/packages/client/src/themes/d-green-orange.json5 b/packages/client/src/themes/d-green-orange.json5 new file mode 100644 index 0000000000..62adc39e29 --- /dev/null +++ b/packages/client/src/themes/d-green-orange.json5 @@ -0,0 +1,24 @@ +{ + id: 'dc489603-27b5-424a-9b25-1ff6aec9824a', + + name: 'Mi Green+Orange Dark', + author: 'syuilo', + + base: 'dark', + + props: { + accent: '#e97f00', + bg: '#0C1210', + fg: '#dee7e4', + fgHighlighted: '#fff', + fgOnAccent: '#192320', + divider: '#e7fffb24', + panel: '#192320', + panelHeaderBg: '@panel', + panelHeaderDivider: '@divider', + popup: '#293330', + renote: '@accent', + mentionMe: '#b4e900', + link: '#24d7ce', + }, +} diff --git a/packages/client/src/themes/d-pumpkin.json5 b/packages/client/src/themes/d-pumpkin.json5 deleted file mode 100644 index 064ca4577b..0000000000 --- a/packages/client/src/themes/d-pumpkin.json5 +++ /dev/null @@ -1,88 +0,0 @@ -{ - id: '0b64fef3-02c7-20b5-dd87-b3f77e2b4301', - - name: 'Mi Pumpkin Dark', - author: 'syuilo', - - base: 'dark', - - props: { - X2: ':darken<2<@panel', - X3: 'rgba(255, 255, 255, 0.05)', - X4: 'rgba(255, 255, 255, 0.1)', - X5: 'rgba(255, 255, 255, 0.05)', - X6: 'rgba(255, 255, 255, 0.15)', - X7: 'rgba(255, 255, 255, 0.05)', - X8: ':lighten<5<@accent', - X9: ':darken<5<@accent', - bg: 'rgb(37, 32, 47)', - fg: '#e0d5c0', - X10: ':alpha<0.4<@accent', - X11: 'rgba(0, 0, 0, 0.3)', - X12: 'rgba(255, 255, 255, 0.1)', - X13: 'rgba(255, 255, 255, 0.15)', - X14: ':alpha<0.5<@navBg', - X15: ':alpha<0<@panel', - X16: ':alpha<0.7<@panel', - X17: ':alpha<0.8<@bg', - cwBg: '#687390', - cwFg: '#393f4f', - link: 'rgb(172, 193, 68)', - warn: '#ecb637', - badge: '#31b1ce', - error: '#ec4137', - focus: ':alpha<0.3<@accent', - navBg: '@panel', - navFg: '@fg', - panel: ':lighten<3<@bg', - popup: ':lighten<3<@panel', - accent: 'rgb(242, 133, 36)', - header: ':alpha<0.7<@panel', - infoBg: '#253142', - infoFg: '#fff', - renote: 'rgb(110, 179, 72)', - shadow: 'rgba(0, 0, 0, 0.3)', - divider: 'rgba(255, 255, 255, 0.1)', - hashtag: 'rgb(188, 90, 255)', - mention: 'rgb(72, 179, 139)', - modalBg: 'rgba(0, 0, 0, 0.5)', - success: '#86b300', - buttonBg: 'rgba(255, 255, 255, 0.05)', - switchBg: 'rgba(255, 255, 255, 0.15)', - acrylicBg: ':alpha<0.5<@bg', - cwHoverBg: '#707b97', - indicator: '@accent', - mentionMe: '@accent', - messageBg: '@bg', - navActive: '@accent', - accentedBg: ':alpha<0.15<@accent', - fgOnAccent: '#000', - infoWarnBg: '#42321c', - infoWarnFg: '#ffbd3e', - navHoverFg: ':lighten<17<@fg', - dateLabelFg: '@fg', - inputBorder: 'rgba(255, 255, 255, 0.1)', - panelBorder: '" solid 1px var(--divider)', - accentDarken: ':darken<10<@accent', - acrylicPanel: ':alpha<0.5<@panel', - navIndicator: '@indicator', - accentLighten: ':lighten<10<@accent', - buttonHoverBg: 'rgba(255, 255, 255, 0.1)', - driveFolderBg: ':alpha<0.3<@accent', - fgHighlighted: ':lighten<3<@fg', - fgTransparent: ':alpha<0.5<@fg', - panelHeaderBg: ':lighten<3<@panel', - panelHeaderFg: '@fg', - buttonGradateA: '@accent', - buttonGradateB: ':hue<20<@accent', - htmlThemeColor: '@bg', - panelHighlight: ':lighten<3<@panel', - listItemHoverBg: 'rgba(255, 255, 255, 0.03)', - scrollbarHandle: 'rgba(255, 255, 255, 0.2)', - inputBorderHover: 'rgba(255, 255, 255, 0.2)', - wallpaperOverlay: 'rgba(0, 0, 0, 0.5)', - fgTransparentWeak: ':alpha<0.75<@fg', - panelHeaderDivider: 'rgba(0, 0, 0, 0)', - scrollbarHandleHover: 'rgba(255, 255, 255, 0.4)', - }, -} diff --git a/packages/client/src/ui/_common_/statusbars.vue b/packages/client/src/ui/_common_/statusbars.vue index 80949665b3..e50b4e54c3 100644 --- a/packages/client/src/ui/_common_/statusbars.vue +++ b/packages/client/src/ui/_common_/statusbars.vue @@ -64,7 +64,7 @@ const XUserList = defineAsyncComponent(() => import('./statusbar-user-list.vue') width: 100%; line-height: var(--height); height: var(--height); - overflow: hidden; overflow: clip; + overflow: clip; contain: strict; > .name { diff --git a/packages/client/src/ui/classic.vue b/packages/client/src/ui/classic.vue index a2c26f536e..70db7ed12b 100644 --- a/packages/client/src/ui/classic.vue +++ b/packages/client/src/ui/classic.vue @@ -241,7 +241,7 @@ onMounted(() => { border-left: solid 1px var(--divider); border-right: solid 1px var(--divider); border-radius: 0; - overflow: hidden; overflow: clip; + overflow: clip; --margin: 12px; } diff --git a/packages/client/src/ui/deck/list-column.vue b/packages/client/src/ui/deck/list-column.vue index 843a3bd1cb..a27e65594a 100644 --- a/packages/client/src/ui/deck/list-column.vue +++ b/packages/client/src/ui/deck/list-column.vue @@ -9,7 +9,7 @@ </template> <script lang="ts" setup> -import { } from 'vue'; +import { } from 'vue'; import XColumn from './column.vue'; import XTimeline from '@/components/timeline.vue'; import * as os from '@/os'; diff --git a/packages/client/src/widgets/activity.chart.vue b/packages/client/src/widgets/activity.chart.vue index b7db2af580..b61e419f94 100644 --- a/packages/client/src/widgets/activity.chart.vue +++ b/packages/client/src/widgets/activity.chart.vue @@ -39,15 +39,15 @@ let pointsRenote: any = $ref(null); let pointsTotal: any = $ref(null); function dragListen(fn) { - window.addEventListener('mousemove', fn); + window.addEventListener('mousemove', fn); window.addEventListener('mouseleave', dragClear.bind(null, fn)); - window.addEventListener('mouseup', dragClear.bind(null, fn)); + window.addEventListener('mouseup', dragClear.bind(null, fn)); } function dragClear(fn) { - window.removeEventListener('mousemove', fn); + window.removeEventListener('mousemove', fn); window.removeEventListener('mouseleave', dragClear); - window.removeEventListener('mouseup', dragClear); + window.removeEventListener('mouseup', dragClear); } function onMousedown(ev) { diff --git a/packages/client/vite.config.ts b/packages/client/vite.config.ts index 5800cf5021..f23c621131 100644 --- a/packages/client/vite.config.ts +++ b/packages/client/vite.config.ts @@ -49,6 +49,7 @@ export default defineConfig(({ command, mode }) => { 'chrome100', 'firefox100', 'safari15', + 'es2017', // TODO: そのうち消す ], manifest: 'manifest.json', rollupOptions: { diff --git a/packages/client/yarn.lock b/packages/client/yarn.lock index e5459b8dda..3cef5b87cc 100644 --- a/packages/client/yarn.lock +++ b/packages/client/yarn.lock @@ -515,14 +515,14 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.0.tgz#524a11e15c09701733033c96943ecf33f55d9ca1" - integrity sha512-lvhRJ2pGe2V9MEU46ELTdiHgiAFZPKtLhiU5wlnaYpMc2+c1R8fh8i80ZAa665drvjHKUJyRRGg3gEm1If54ow== +"@typescript-eslint/eslint-plugin@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.6.tgz#9c6017b6c1d04894141b4a87816388967f64c359" + integrity sha512-J4zYMIhgrx4MgnZrSDD7sEnQp7FmhKNOaqaOpaoQ/SfdMfRB/0yvK74hTnvH+VQxndZynqs5/Hn4t+2/j9bADg== dependencies: - "@typescript-eslint/scope-manager" "5.30.0" - "@typescript-eslint/type-utils" "5.30.0" - "@typescript-eslint/utils" "5.30.0" + "@typescript-eslint/scope-manager" "5.30.6" + "@typescript-eslint/type-utils" "5.30.6" + "@typescript-eslint/utils" "5.30.6" debug "^4.3.4" functional-red-black-tree "^1.0.1" ignore "^5.2.0" @@ -530,69 +530,69 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/parser@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.30.0.tgz#a2184fb5f8ef2bf1db0ae61a43907e2e32aa1b8f" - integrity sha512-2oYYUws5o2liX6SrFQ5RB88+PuRymaM2EU02/9Ppoyu70vllPnHVO7ioxDdq/ypXHA277R04SVjxvwI8HmZpzA== +"@typescript-eslint/parser@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.30.6.tgz#add440db038fa9d777e4ebdaf66da9e7fb7abe92" + integrity sha512-gfF9lZjT0p2ZSdxO70Xbw8w9sPPJGfAdjK7WikEjB3fcUI/yr9maUVEdqigBjKincUYNKOmf7QBMiTf719kbrA== dependencies: - "@typescript-eslint/scope-manager" "5.30.0" - "@typescript-eslint/types" "5.30.0" - "@typescript-eslint/typescript-estree" "5.30.0" + "@typescript-eslint/scope-manager" "5.30.6" + "@typescript-eslint/types" "5.30.6" + "@typescript-eslint/typescript-estree" "5.30.6" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.30.0.tgz#bf585ee801ab4ad84db2f840174e171a6bb002c7" - integrity sha512-3TZxvlQcK5fhTBw5solQucWSJvonXf5yua5nx8OqK94hxdrT7/6W3/CS42MLd/f1BmlmmbGEgQcTHHCktUX5bQ== +"@typescript-eslint/scope-manager@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.30.6.tgz#ce1b49ff5ce47f55518d63dbe8fc9181ddbd1a33" + integrity sha512-Hkq5PhLgtVoW1obkqYH0i4iELctEKixkhWLPTYs55doGUKCASvkjOXOd/pisVeLdO24ZX9D6yymJ/twqpJiG3g== dependencies: - "@typescript-eslint/types" "5.30.0" - "@typescript-eslint/visitor-keys" "5.30.0" + "@typescript-eslint/types" "5.30.6" + "@typescript-eslint/visitor-keys" "5.30.6" -"@typescript-eslint/type-utils@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.30.0.tgz#98f3af926a5099153f092d4dad87148df21fbaae" - integrity sha512-GF8JZbZqSS+azehzlv/lmQQ3EU3VfWYzCczdZjJRxSEeXDQkqFhCBgFhallLDbPwQOEQ4MHpiPfkjKk7zlmeNg== +"@typescript-eslint/type-utils@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.30.6.tgz#a64aa9acbe609ab77f09f53434a6af2b9685f3af" + integrity sha512-GFVVzs2j0QPpM+NTDMXtNmJKlF842lkZKDSanIxf+ArJsGeZUIaeT4jGg+gAgHt7AcQSFwW7htzF/rbAh2jaVA== dependencies: - "@typescript-eslint/utils" "5.30.0" + "@typescript-eslint/utils" "5.30.6" debug "^4.3.4" tsutils "^3.21.0" -"@typescript-eslint/types@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.30.0.tgz#db7d81d585a3da3801432a9c1d2fafbff125e110" - integrity sha512-vfqcBrsRNWw/LBXyncMF/KrUTYYzzygCSsVqlZ1qGu1QtGs6vMkt3US0VNSQ05grXi5Yadp3qv5XZdYLjpp8ag== +"@typescript-eslint/types@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.30.6.tgz#86369d0a7af8c67024115ac1da3e8fb2d38907e1" + integrity sha512-HdnP8HioL1F7CwVmT4RaaMX57RrfqsOMclZc08wGMiDYJBsLGBM7JwXM4cZJmbWLzIR/pXg1kkrBBVpxTOwfUg== -"@typescript-eslint/typescript-estree@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.0.tgz#4565ee8a6d2ac368996e20b2344ea0eab1a8f0bb" - integrity sha512-hDEawogreZB4n1zoqcrrtg/wPyyiCxmhPLpZ6kmWfKF5M5G0clRLaEexpuWr31fZ42F96SlD/5xCt1bT5Qm4Nw== +"@typescript-eslint/typescript-estree@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.6.tgz#a84a0d6a486f9b54042da1de3d671a2c9f14484e" + integrity sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A== dependencies: - "@typescript-eslint/types" "5.30.0" - "@typescript-eslint/visitor-keys" "5.30.0" + "@typescript-eslint/types" "5.30.6" + "@typescript-eslint/visitor-keys" "5.30.6" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/utils@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.30.0.tgz#1dac771fead5eab40d31860716de219356f5f754" - integrity sha512-0bIgOgZflLKIcZsWvfklsaQTM3ZUbmtH0rJ1hKyV3raoUYyeZwcjQ8ZUJTzS7KnhNcsVT1Rxs7zeeMHEhGlltw== +"@typescript-eslint/utils@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.30.6.tgz#1de2da14f678e7d187daa6f2e4cdb558ed0609dc" + integrity sha512-xFBLc/esUbLOJLk9jKv0E9gD/OH966M40aY9jJ8GiqpSkP2xOV908cokJqqhVd85WoIvHVHYXxSFE4cCSDzVvA== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.30.0" - "@typescript-eslint/types" "5.30.0" - "@typescript-eslint/typescript-estree" "5.30.0" + "@typescript-eslint/scope-manager" "5.30.6" + "@typescript-eslint/types" "5.30.6" + "@typescript-eslint/typescript-estree" "5.30.6" eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/visitor-keys@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.0.tgz#07721d23daca2ec4c2da7f1e660d41cd78bacac3" - integrity sha512-6WcIeRk2DQ3pHKxU1Ni0qMXJkjO/zLjBymlYBy/53qxe7yjEFSvzKLDToJjURUhSl2Fzhkl4SMXQoETauF74cw== +"@typescript-eslint/visitor-keys@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.6.tgz#94dd10bb481c8083378d24de1742a14b38a2678c" + integrity sha512-41OiCjdL2mCaSDi2SvYbzFLlqqlm5v1ZW9Ym55wXKL/Rx6OOB1IbuFGo71Fj6Xy90gJDFTlgOS+vbmtGHPTQQA== dependencies: - "@typescript-eslint/types" "5.30.0" + "@typescript-eslint/types" "5.30.6" eslint-visitor-keys "^3.3.0" "@ungap/promise-all-settled@1.1.2": @@ -600,10 +600,10 @@ resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== -"@vitejs/plugin-vue@3.0.0-beta.1": - version "3.0.0-beta.1" - resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-3.0.0-beta.1.tgz#65a6be6ed619955a5edea6115dedcfc5da4ed3f6" - integrity sha512-cPVQHIKZkVEQ8qW7+BlbTrGJXNpP2aMKzVhQdTnWK9u6cSDmVdZOXHmKPO2KVvrNpFXXS8R7hHBXMsSApA+XOA== +"@vitejs/plugin-vue@3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-3.0.0.tgz#7081e2b3fbe04e291bb85107b9fb57a1fa5e6aeb" + integrity sha512-yWP34ArFh/jAeNUDkkLz/kVRLjf5ppJiq4L36f64Cp6dIrMQeYZGDP9xxdemlXfZR9ylN9JgHUl3GzfqOtgYDg== "@vue/compiler-core@3.2.37": version "3.2.37" @@ -1715,10 +1715,10 @@ eslint-plugin-import@2.26.0: resolve "^1.22.0" tsconfig-paths "^3.14.1" -eslint-plugin-vue@9.1.1: - version "9.1.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.1.1.tgz#341f7533cb041958455138834341d5be01f9f327" - integrity sha512-W9n5PB1X2jzC7CK6riG0oAcxjmKrjTF6+keL1rni8n57DZeilx/Fulz+IRJK3lYseLNAygN0I62L7DvioW40Tw== +eslint-plugin-vue@9.2.0: + version "9.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.2.0.tgz#b7ca02b2ce8218b7586346440fc61c2655db353a" + integrity sha512-W2hc+NUXoce8sZtWgZ45miQTy6jNyuSdub5aZ1IBune4JDeAyzucYX0TzkrQ1jMO52sNUDYlCIHDoaNePe0p5g== dependencies: eslint-utils "^3.0.0" natural-compare "^1.4.0" @@ -1761,10 +1761,10 @@ eslint-visitor-keys@^3.3.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@8.18.0: - version "8.18.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.18.0.tgz#78d565d16c993d0b73968c523c0446b13da784fd" - integrity sha512-As1EfFMVk7Xc6/CvhssHUjsAQSkpfXvUGMFC3ce8JDe6WvqCgRrLOBQbVpsBFr1X1V+RACOadnzVvcUS5ni2bA== +eslint@8.19.0: + version "8.19.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.19.0.tgz#7342a3cbc4fbc5c106a1eefe0fd0b50b6b1a7d28" + integrity sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw== dependencies: "@eslint/eslintrc" "^1.3.0" "@humanwhocodes/config-array" "^0.9.2" @@ -2866,12 +2866,12 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -mfm-js@0.22.1: - version "0.22.1" - resolved "https://registry.yarnpkg.com/mfm-js/-/mfm-js-0.22.1.tgz#ad5f0b95cc903ca5a5e414e2edf64ac4648dc8c2" - integrity sha512-UV5zvDKlWPpBFeABhyCzuOTJ3RwrNrmVpJ+zz/dFX6D/ntEywljgxkfsLamcy0ZSwUAr0O+WQxGHvAwyxUgsAQ== +mfm-js@0.23.0-canary.1: + version "0.23.0-canary.1" + resolved "https://registry.yarnpkg.com/mfm-js/-/mfm-js-0.23.0-canary.1.tgz#1b7b7635f18bed9776054406b72e6bd613c8d0eb" + integrity sha512-SkMrW1rQAv+mFGtLKN9DSv6vxSREDu8ChmkBl1Ch5sQfp47BhuvcRg5EKGmt3WAQRAOylXYMg8wVYR7C5BHKeA== dependencies: - twemoji-parser "14.0.x" + twemoji-parser "14.0.0" micromatch@^4.0.2: version "4.0.2" @@ -3649,7 +3649,14 @@ rndstr@1.0.0: rangestr "0.0.1" seedrandom "2.4.2" -rollup@2.75.7, rollup@^2.75.6: +rollup@2.76.0: + version "2.76.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.76.0.tgz#c69fe03db530ac53fcb9523b3caa0d3c0b9491a1" + integrity sha512-9jwRIEY1jOzKLj3nsY/yot41r19ITdQrhs+q3ggNWhr9TQgduHqANvPpS32RNpzGklJu3G1AJfvlZLi/6wFgWA== + optionalDependencies: + fsevents "~2.3.2" + +rollup@^2.75.6: version "2.75.7" resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.75.7.tgz#221ff11887ae271e37dcc649ba32ce1590aaa0b9" integrity sha512-VSE1iy0eaAYNCxEXaleThdFXqZJ42qDBatAwrfnPlENEZ8erQ+0LYX4JXOLPceWfZpV1VtZwZ3dFCuOZiSyFtQ== @@ -4085,7 +4092,7 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= -twemoji-parser@14.0.0, twemoji-parser@14.0.x: +twemoji-parser@14.0.0: version "14.0.0" resolved "https://registry.yarnpkg.com/twemoji-parser/-/twemoji-parser-14.0.0.tgz#13dabcb6d3a261d9efbf58a1666b182033bf2b62" integrity sha512-9DUOTGLOWs0pFWnh1p6NF+C3CkQ96PWmEFwhOVmT3WbecRC+68AIqpsnJXygfkFcp4aXbOp8Dwbhh/HQgvoRxA== @@ -4215,10 +4222,10 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -vite@3.0.0-beta.7: - version "3.0.0-beta.7" - resolved "https://registry.yarnpkg.com/vite/-/vite-3.0.0-beta.7.tgz#ded6483ef3b9b16dbe3a912a35accb9cc3498530" - integrity sha512-yjw154hB229qq5Bl6+/CJSTxC/yIDmDJbaAjE/pdracz3jytNEd2ovk5BvxgZT6+qPiUc2rRH3FgGqiZnweIFw== +vite@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/vite/-/vite-3.0.0.tgz#b4675cb9ab83ec0803b9c952ffa6519bcce033a7" + integrity sha512-M7phQhY3+fRZa0H+1WzI6N+/onruwPTBTMvaj7TzgZ0v2TE+N2sdLKxJOfOv9CckDWt5C4HmyQP81xB4dwRKzA== dependencies: esbuild "^0.14.47" postcss "^8.4.14" diff --git a/packages/shared/.eslintrc.js b/packages/shared/.eslintrc.js index 3aef6484e9..aed822be9a 100644 --- a/packages/shared/.eslintrc.js +++ b/packages/shared/.eslintrc.js @@ -53,7 +53,6 @@ module.exports = { 'no-empty-pattern': ['warn'], 'no-async-promise-executor': ['off'], 'no-useless-escape': ['off'], - 'no-multi-spaces': ['warn'], 'no-multiple-empty-lines': ['error', { 'max': 1 }], 'no-control-regex': ['warn'], 'no-empty': ['warn'], diff --git a/packages/sw/src/sw.ts b/packages/sw/src/sw.ts index 0ba6a6e4af..872692f903 100644 --- a/packages/sw/src/sw.ts +++ b/packages/sw/src/sw.ts @@ -42,8 +42,12 @@ self.addEventListener('push', ev => { // case 'driveFileCreated': case 'notification': case 'unreadMessagingMessage': + // 1日以上経過している場合は無視 + if ((new Date()).getTime() - data.dateTime > 1000 * 60 * 60 * 24) break; + // クライアントがあったらストリームに接続しているということなので通知しない - if (clients.length != 0) return; + if (clients.length !== 0) break; + return createNotification(data); case 'readAllNotifications': for (const n of await self.registration.getNotifications()) { diff --git a/packages/sw/src/types.ts b/packages/sw/src/types.ts index 6aa3726eac..0404e21e57 100644 --- a/packages/sw/src/types.ts +++ b/packages/sw/src/types.ts @@ -24,6 +24,7 @@ export type pushNotificationData<K extends keyof pushNotificationDataSourceMap> type: K; body: pushNotificationDataSourceMap[K]; userId: string; + dateTime: number; }; export type pushNotificationDataMap = { @@ -194,48 +194,48 @@ dependencies: "@types/node" "*" -"@typescript-eslint/parser@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.30.0.tgz#a2184fb5f8ef2bf1db0ae61a43907e2e32aa1b8f" - integrity sha512-2oYYUws5o2liX6SrFQ5RB88+PuRymaM2EU02/9Ppoyu70vllPnHVO7ioxDdq/ypXHA277R04SVjxvwI8HmZpzA== +"@typescript-eslint/parser@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.30.6.tgz#add440db038fa9d777e4ebdaf66da9e7fb7abe92" + integrity sha512-gfF9lZjT0p2ZSdxO70Xbw8w9sPPJGfAdjK7WikEjB3fcUI/yr9maUVEdqigBjKincUYNKOmf7QBMiTf719kbrA== dependencies: - "@typescript-eslint/scope-manager" "5.30.0" - "@typescript-eslint/types" "5.30.0" - "@typescript-eslint/typescript-estree" "5.30.0" + "@typescript-eslint/scope-manager" "5.30.6" + "@typescript-eslint/types" "5.30.6" + "@typescript-eslint/typescript-estree" "5.30.6" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.30.0.tgz#bf585ee801ab4ad84db2f840174e171a6bb002c7" - integrity sha512-3TZxvlQcK5fhTBw5solQucWSJvonXf5yua5nx8OqK94hxdrT7/6W3/CS42MLd/f1BmlmmbGEgQcTHHCktUX5bQ== +"@typescript-eslint/scope-manager@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.30.6.tgz#ce1b49ff5ce47f55518d63dbe8fc9181ddbd1a33" + integrity sha512-Hkq5PhLgtVoW1obkqYH0i4iELctEKixkhWLPTYs55doGUKCASvkjOXOd/pisVeLdO24ZX9D6yymJ/twqpJiG3g== dependencies: - "@typescript-eslint/types" "5.30.0" - "@typescript-eslint/visitor-keys" "5.30.0" + "@typescript-eslint/types" "5.30.6" + "@typescript-eslint/visitor-keys" "5.30.6" -"@typescript-eslint/types@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.30.0.tgz#db7d81d585a3da3801432a9c1d2fafbff125e110" - integrity sha512-vfqcBrsRNWw/LBXyncMF/KrUTYYzzygCSsVqlZ1qGu1QtGs6vMkt3US0VNSQ05grXi5Yadp3qv5XZdYLjpp8ag== +"@typescript-eslint/types@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.30.6.tgz#86369d0a7af8c67024115ac1da3e8fb2d38907e1" + integrity sha512-HdnP8HioL1F7CwVmT4RaaMX57RrfqsOMclZc08wGMiDYJBsLGBM7JwXM4cZJmbWLzIR/pXg1kkrBBVpxTOwfUg== -"@typescript-eslint/typescript-estree@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.0.tgz#4565ee8a6d2ac368996e20b2344ea0eab1a8f0bb" - integrity sha512-hDEawogreZB4n1zoqcrrtg/wPyyiCxmhPLpZ6kmWfKF5M5G0clRLaEexpuWr31fZ42F96SlD/5xCt1bT5Qm4Nw== +"@typescript-eslint/typescript-estree@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.6.tgz#a84a0d6a486f9b54042da1de3d671a2c9f14484e" + integrity sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A== dependencies: - "@typescript-eslint/types" "5.30.0" - "@typescript-eslint/visitor-keys" "5.30.0" + "@typescript-eslint/types" "5.30.6" + "@typescript-eslint/visitor-keys" "5.30.6" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/visitor-keys@5.30.0": - version "5.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.0.tgz#07721d23daca2ec4c2da7f1e660d41cd78bacac3" - integrity sha512-6WcIeRk2DQ3pHKxU1Ni0qMXJkjO/zLjBymlYBy/53qxe7yjEFSvzKLDToJjURUhSl2Fzhkl4SMXQoETauF74cw== +"@typescript-eslint/visitor-keys@5.30.6": + version "5.30.6" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.6.tgz#94dd10bb481c8083378d24de1742a14b38a2678c" + integrity sha512-41OiCjdL2mCaSDi2SvYbzFLlqqlm5v1ZW9Ym55wXKL/Rx6OOB1IbuFGo71Fj6Xy90gJDFTlgOS+vbmtGHPTQQA== dependencies: - "@typescript-eslint/types" "5.30.0" + "@typescript-eslint/types" "5.30.6" eslint-visitor-keys "^3.3.0" aggregate-error@^3.0.0: |