summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2023-02-08 18:03:28 +0900
committersyuilo <Syuilotan@yahoo.co.jp>2023-02-08 18:03:28 +0900
commit03744a25ed4d3d9137e5382c8eaaac88a6b5ec17 (patch)
tree5c4759905f11f267d7570a283386a78adbbd2ec2
parentMerge branch 'develop' (diff)
parent13.5.0 (diff)
downloadmisskey-03744a25ed4d3d9137e5382c8eaaac88a6b5ec17.tar.gz
misskey-03744a25ed4d3d9137e5382c8eaaac88a6b5ec17.tar.bz2
misskey-03744a25ed4d3d9137e5382c8eaaac88a6b5ec17.zip
Merge branch 'develop'
-rw-r--r--CHANGELOG.md15
-rw-r--r--Dockerfile7
-rw-r--r--healthcheck.sh2
-rw-r--r--locales/it-IT.yml13
-rw-r--r--locales/lo-LA.yml70
-rw-r--r--locales/th-TH.yml4
-rw-r--r--locales/uk-UA.yml4
-rw-r--r--locales/zh-TW.yml16
-rw-r--r--package.json8
-rw-r--r--packages/backend/ormconfig.js2
-rw-r--r--packages/backend/src/GlobalModule.ts4
-rw-r--r--packages/backend/src/core/CustomEmojiService.ts8
-rw-r--r--packages/backend/src/core/activitypub/models/ApImageService.ts4
-rw-r--r--packages/backend/src/core/activitypub/models/ApNoteService.ts17
-rw-r--r--packages/backend/src/core/activitypub/models/ApPersonService.ts16
-rw-r--r--packages/backend/src/core/entities/DriveFileEntityService.ts18
-rw-r--r--packages/backend/src/core/entities/UserEntityService.ts2
-rw-r--r--packages/backend/src/postgres.ts (renamed from packages/backend/src/postgre.ts)2
-rw-r--r--packages/backend/test/utils.ts2
-rw-r--r--packages/frontend/src/components/MkAbuseReport.vue2
-rw-r--r--packages/frontend/src/components/MkAutocomplete.vue2
-rw-r--r--packages/frontend/src/components/MkEmojiPicker.vue7
-rw-r--r--packages/frontend/src/components/MkMediaBanner.vue31
-rw-r--r--packages/frontend/src/components/MkMediaList.vue120
-rw-r--r--packages/frontend/src/components/MkMediaVideo.vue4
-rw-r--r--packages/frontend/src/components/MkMenu.vue2
-rw-r--r--packages/frontend/src/components/MkNote.vue4
-rw-r--r--packages/frontend/src/components/MkNoteDetailed.vue6
-rw-r--r--packages/frontend/src/components/MkNoteHeader.vue2
-rw-r--r--packages/frontend/src/components/MkNotePreview.vue2
-rw-r--r--packages/frontend/src/components/MkNotification.vue2
-rw-r--r--packages/frontend/src/components/MkReactionsViewer.details.vue2
-rw-r--r--packages/frontend/src/components/MkUserCardMini.vue2
-rw-r--r--packages/frontend/src/components/MkUserInfo.vue5
-rw-r--r--packages/frontend/src/components/MkUserPreview.vue2
-rw-r--r--packages/frontend/src/components/MkUserSelectDialog.vue4
-rw-r--r--packages/frontend/src/components/MkUsersTooltip.vue2
-rw-r--r--packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.vue9
-rw-r--r--packages/frontend/src/components/global/MkPageHeader.vue2
-rw-r--r--packages/frontend/src/components/global/MkUserName.vue15
-rw-r--r--packages/frontend/src/components/index.ts3
-rw-r--r--packages/frontend/src/components/mfm.ts2
-rw-r--r--packages/frontend/src/pages/clip.vue2
-rw-r--r--packages/frontend/src/pages/follow-requests.vue2
-rw-r--r--packages/frontend/src/pages/gallery/post.vue2
-rw-r--r--packages/frontend/src/pages/messaging/index.vue2
-rw-r--r--packages/frontend/src/pages/my-lists/list.vue2
-rw-r--r--packages/frontend/src/pages/note.vue2
-rw-r--r--packages/frontend/src/pages/page.vue2
-rw-r--r--packages/frontend/src/pages/settings/accounts.vue4
-rw-r--r--packages/frontend/src/pages/user-info.vue2
-rw-r--r--packages/frontend/src/pages/user/home.vue4
-rw-r--r--packages/frontend/src/store.ts2
-rw-r--r--packages/frontend/src/style.scss7
-rw-r--r--packages/frontend/src/widgets/WidgetProfile.vue4
55 files changed, 277 insertions, 206 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7142695350..00d69dbd19 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,21 @@
You should also include the user name that made the change.
-->
+## 13.5.0 (2023/02/08)
+
+### Changes
+- perf(client): do not render custom emojis in user names
+
+### Improvements
+- Client: disableShowingAnimatedImagesのデフォルト値をprefers-reduced-motionにする
+- enhance(client): tweak medialist style
+
+### Bugfixes
+- fix docker health check
+- Client: MkEmojiPickerでもChromeで検索ダイアログで変換確定するとそのまま検索されてしまうのを修正
+- fix(mfm): default degree not used in rotate
+- fix(server): validate urls from ap to improve security
+
## 13.4.0 (2023/02/05)
### Improvements
diff --git a/Dockerfile b/Dockerfile
index 89a8d38f8c..0bfd24bd9a 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -8,9 +8,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache \
&& apt-get update \
&& apt-get install -yqq --no-install-recommends \
- build-essential wget ca-certificates \
- && wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq \
- && chmod +x /usr/bin/yq
+ build-essential
RUN corepack enable
@@ -44,7 +42,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
- ffmpeg tini \
+ ffmpeg tini curl \
&& corepack enable \
&& groupadd -g "${GID}" misskey \
&& useradd -l -u "${UID}" -g "${GID}" -m -d /misskey misskey \
@@ -54,7 +52,6 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
USER misskey
WORKDIR /misskey
-COPY --from=builder /usr/bin/yq /usr/bin/yq
COPY --chown=misskey:misskey --from=builder /misskey/node_modules ./node_modules
COPY --chown=misskey:misskey --from=builder /misskey/built ./built
COPY --chown=misskey:misskey --from=builder /misskey/packages/backend/node_modules ./packages/backend/node_modules
diff --git a/healthcheck.sh b/healthcheck.sh
index f8e598b282..e97a3f0636 100644
--- a/healthcheck.sh
+++ b/healthcheck.sh
@@ -1,4 +1,4 @@
#!/bin/bash
-PORT=$(yq '.port' /misskey/.config/default.yml)
+PORT=$(grep '^port:' /misskey/.config/default.yml | awk 'NR==1{print $2; exit}')
curl -s -S -o /dev/null "http://localhost:${PORT}"
diff --git a/locales/it-IT.yml b/locales/it-IT.yml
index 66af4654cc..701fb7eef3 100644
--- a/locales/it-IT.yml
+++ b/locales/it-IT.yml
@@ -1044,7 +1044,7 @@ _achievements:
flavor: "Grazie per aver usato Misskey!"
_noteClipped1:
title: "Devo clippare!"
- description: "Ho raccolto in Clip la prima Nota"
+ description: "Hai raccolto la tua prima Nota in una Clip"
_noteFavorited1:
title: "Guarda le stelle"
description: "Aggiungi una Nota ai preferiti per la prima volta"
@@ -1080,7 +1080,7 @@ _achievements:
title: "Follow me!"
description: "Hai ottenuto 10 profili Follower"
_followers50:
- title: "Follower a frotte"
+ title: "Un gregge di Follower"
description: "Hai ottenuto 50 Follower"
_followers100:
title: "Popolare"
@@ -1108,7 +1108,7 @@ _achievements:
title: "Caccia al tesoro"
description: "Hai trovato un tesoro nascosto"
_client30min:
- title: "Piccola pausa"
+ title: "Piccola grande pausa"
description: "Hai passato più di 30 minuti su Misskey"
_noteDeletedWithin1min:
title: "Ooops!"
@@ -1134,7 +1134,7 @@ _achievements:
title: "Hello, world!"
description: "Hai scritto «Hello world» nel blocco appunti"
_open3windows:
- title: "Finestrato"
+ title: "Apri le finestre!"
description: "Hai aperto almeno 3 finestre contemporaneamente"
_driveFolderCircularReference:
title: "Riferimento circolare"
@@ -1170,7 +1170,7 @@ _achievements:
_cookieClicked:
title: "Clicca il biscotto"
description: "Hai giocato a cliccare il cookie"
- flavor: "Hai autorizzato i cookie?"
+ flavor: "È il sito giusto?"
_brainDiver:
title: "Brain Diver"
description: "Pubblica un link a Brain Diver"
@@ -1195,6 +1195,9 @@ _role:
baseRole: "Ruolo di base"
useBaseValue: "Eredita dal ruolo base"
chooseRoleToAssign: "Seleziona il ruolo da assegnare"
+ iconUrl: "URL dell'icona"
+ asBadge: "Mostra come badge"
+ descriptionOfAsBadge: "Se indicato, accanto al nome utente viene visualizzata l'icona del ruolo."
canEditMembersByModerator: "Anche i Moderatori assegnano profili a questo ruolo"
descriptionOfCanEditMembersByModerator: "Se disattivo, potranno farlo solamente gli Amministratori."
priority: "Priorità"
diff --git a/locales/lo-LA.yml b/locales/lo-LA.yml
index a46ddcc10f..ae938835e8 100644
--- a/locales/lo-LA.yml
+++ b/locales/lo-LA.yml
@@ -1,2 +1,72 @@
---
_lang_: "ພາສາລາວ"
+headlineMisskey: "ເຊື່ອມຕໍ່ເຄືອຂ່າຍໂດຍຫມາຍເຫດ"
+introMisskey: "ຍິນດີຕ້ອນຮັບ! Misskey ເປັນແຫຼ່ງເປີດ, ການບໍລິການ microblogging ກະຈາຍ\nສ້າງ \"ບັນທຶກ\" ເພື່ອແບ່ງປັນຄວາມຄິດຂອງທ່ານກັບທຸກໆຄົນທີ່ຢູ່ອ້ອມຮອບທ່ານ 📡\nດ້ວຍ \"ປະຕິກິລິຍາ\", ທ່ານຍັງສາມາດສະແດງຄວາມຮູ້ສຶກຂອງທ່ານຢ່າງໄວວາກ່ຽວກັບບັນທຶກຂອງທຸກໆຄົນ 👍\nມາສຳຫຼວດໂລກໃໝ່! 🚀"
+poweredByMisskeyDescription: "{name} ແມ່ນສ່ວນໜຶ່ງຂອງການບໍລິການທີ່ຂັບເຄື່ອນໂດຍແພລດຟອມ open source. <b>Misskey</b> (ເອີ້ນວ່າ \"Misskey instance\")"
+monthAndDay: "{ເດືອນ}/{ມື້}"
+search: "ຄົ້ນຫາ"
+notifications: "ການແຈ້ງເຕືອນ"
+username: "ຊື່ຜູ້ໃຊ້"
+password: "ລະຫັດຜ່ານ"
+forgotPassword: "ລືມລະຫັດຜ່ານ"
+fetchingAsApObject: "ກຳລັງດຶງຂໍ້ມູນຈາກ fediverse..."
+ok: "ຕົກ​ລົງ"
+gotIt: "ເຂົ້າໃຈແລ້ວ!"
+cancel: "ຍົກເລີກ"
+noThankYou: "ບໍ່​ແມ່ນ​ຕອນ​ນີ້"
+enterUsername: "ປ້ອນຊື່ຜູ້ໃຊ້"
+renotedBy: "Renoted ໂດຍ {ຜູ້ໃຊ້}"
+noNotes: "ບໍ່ມີຫມາຍເຫດ"
+noNotifications: "ບໍ່ມີການແຈ້ງເຕືອນ"
+instance: "ອີນສະແຕນ"
+settings: "ກຳນົດຄ່າ"
+basicSettings: "ການຕັ້ງຄ່າພື້ນຖານ"
+otherSettings: "ການຕັ້ງຄ່າອື່ນໆ"
+openInWindow: "ເປີດຢູ່ໃນປ່ອງຢ້ຽມ"
+profile: "ໂພຼຟາຍ"
+timeline: "​ເສັ້ນກຳ​ນົດ​ເວ​ລາ​"
+noAccountDescription: "ຜູ້ໃຊ້ນີ້ຍັງບໍ່ໄດ້ຂຽນໃນຊີວະປະຫວັດຂອງເຂົາເຈົ້າເທື່ອ"
+login: "ເຂົ້າ​ສູ່​ລະ​ບົບ"
+loggingIn: "ກຳລັງເຂົ້າສູ່ລະບົບ..."
+logout: "ອອກ​ຈາກ​ລະ​ບົບ"
+signup: "ລົງ​ທະ​ບຽນ"
+uploading: "ການອັບໂຫຼດ..."
+save: "ບັນທຶກ"
+users: "ຜູ້ໃຊ້ຕ່າງໆ"
+addUser: "ເພີ່ມຜູ້ໃຊ້"
+favorite: "ເພີ່ມໃສ່ລາຍການທີ່ມັກ"
+favorites: "ລາຍການທີ່ມັກ"
+unfavorite: "ລຶບອອກຈາກລາຍການທີ່ມັກ"
+favorited: "ເພີ່ມໃສ່ລາຍການທີ່ມັກແລ້ວ"
+alreadyFavorited: "ເພີ່ມເຂົ້າໃນລາຍການທີ່ມັກແລ້ວ."
+cantFavorite: "ບໍ່ສາມາດເພີ່ມໃສ່ລາຍການທີ່ມັກໄດ້."
+pin: "ປັກໝຸດໄປຫາໂປຣໄຟລ໌"
+unpin: "ຖອດປັກໝຸດອອກຈາກໂປຣໄຟລ໌"
+copyContent: "ຄັດລອກເນື້ອຫາ"
+copyLink: "ສຳເນົາລິ້ງ"
+delete: "ລຶບ"
+deleteAndEdit: "ລົບ​ແລະ​ແກ້​ໄຂ​"
+deleteAndEditConfirm: "ເຈົ້າ​ແນ່​ໃຈ​ບໍ່? ທີ່ທ່ານຕ້ອງການທີ່ຈະລຶບບັນທຶກນີ້ແລະແກ້ໄຂມັນ ທ່ານອາດຈະສູນເສຍການໂຕ້ຕອບ, ບັນທຶກ, ແລະການຕອບກັບທັງໝົດ"
+addToList: "ເພີ່ມໃສ່ລາຍຊື່"
+sendMessage: "ສົ່ງຂໍ້ຄວາມ"
+pinned: "ປັກໝຸດໄປຫາໂປຣໄຟລ໌"
+instances: "ອີນສະແຕນ"
+remove: "ລຶບ"
+smtpUser: "ຊື່ຜູ້ໃຊ້"
+smtpPass: "ລະຫັດຜ່ານ"
+user: "ຜູ້ໃຊ້ຕ່າງໆ"
+searchByGoogle: "ຄົ້ນຫາ"
+_mfm:
+ search: "ຄົ້ນຫາ"
+_sfx:
+ notification: "ການແຈ້ງເຕືອນ"
+_widgets:
+ profile: "ໂພຼຟາຍ"
+ notifications: "ການແຈ້ງເຕືອນ"
+ timeline: "​ເສັ້ນກຳ​ນົດ​ເວ​ລາ​"
+_profile:
+ username: "ຊື່ຜູ້ໃຊ້"
+_deck:
+ _columns:
+ notifications: "ການແຈ້ງເຕືອນ"
+ tl: "​ເສັ້ນກຳ​ນົດ​ເວ​ລາ​"
diff --git a/locales/th-TH.yml b/locales/th-TH.yml
index 8087090f5a..98ac29151c 100644
--- a/locales/th-TH.yml
+++ b/locales/th-TH.yml
@@ -1147,7 +1147,7 @@ _achievements:
description: "คุณได้คลิกที่นี่"
_justPlainLucky:
title: "แค่ลัคกี้ธรรมดา"
- description: "มีโอกาสที่จะได้รับด้วยความน่าจะเป็นไปได้ 0.01% ทุก ๆ 10 วินาที"
+ description: "มีโอกาสที่จะได้รับด้วยความน่าจะเป็นไปได้ 0.005% ทุก ๆ 10 วินาที"
_setNameToSyuilo:
title: "พระเจ้าคอมเพล็กซ์"
description: "ตั้งชื่อของคุณเป็น \"syuilo\""
@@ -1182,7 +1182,7 @@ _role:
description: "คำอธิบายบทบาท"
permission: "สิทธิ์ตามบทบาท"
descriptionOfPermission: "<b>ผู้ดูแลกลั่นกรองเนื้อหา</b> สามารถดำเนินการดูแลขั้นพื้นฐานได้นะ\n<b>ผู้ดูแลระบบ</b> สามารถเปลี่ยนการตั้งค่าทั้งหมดของอินสแตนซ์ได้นะ"
- assignTarget: "กำหนดเป้าหมาย"
+ assignTarget: "มอบหมาย"
descriptionOfAssignTarget: "<b>แมนนวล</b> เพื่อเปลี่ยนผู้ที่เป็นส่วนหนึ่งของบทบาทนี้และใครที่ไม่ใช่ด้วยตนเอง\n<b>เงื่อนไข</b> เพื่อให้ผู้ใช้ได้รับการกำหนดและนำออกจากบทบาทนี้โดยอัตโนมัติตามเงื่อนไขชุดหนึ่ง"
manual: "ปรับเอง"
conditional: "มีเงื่อนไข"
diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml
index 52f3f41fcb..d38cab9d14 100644
--- a/locales/uk-UA.yml
+++ b/locales/uk-UA.yml
@@ -1382,8 +1382,8 @@ _tutorial:
step1_1: "Ласкаво просимо!"
step1_2: "Ця сторінка має назву \"стрічка подій\". На ній з'являються записи користувачів на яких ви підписані."
step1_3: "Наразі ваша стрічка порожня, оскільки ви ще не написали жодної нотатки і не підписані на інших."
- step2_1: "Перш ніж зробити запис або підписатись на когось, спочатку заповніть свій обліковий запис."
- step2_2: "Надання деякої інформації про себе дозволить іншим користувачам підписатись на вас."
+ step2_1: "Перш ніж зробити запис або підписатись на когось, заповніть свій профіль."
+ step2_2: "Надання деякої інформації про себе допоможе іншим користувачам вирішити підписатись на вас."
step3_1: "Ви успішно налаштували свій обліковий запис?"
step3_2: "Наступним кроком є написання нотатки. Це можна зробити, натиснувши зображення олівця на екрані."
step3_3: "Після написання вмісту ви можете опублікувати його, натиснувши кнопку у верхньому правому куті форми."
diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml
index 74f3c237fa..ed1e7d8bcb 100644
--- a/locales/zh-TW.yml
+++ b/locales/zh-TW.yml
@@ -326,7 +326,7 @@ connectService: "己連結"
disconnectService: "己斷開 "
enableLocalTimeline: "開啟本地時間軸"
enableGlobalTimeline: "啟用全域時間軸"
-disablingTimelinesInfo: "為了方便,即使您關閉了時間線功能,管理員和審核員仍可以繼續使用。"
+disablingTimelinesInfo: "為了方便,即使您關閉了時間線功能,管理員和審查員仍可以繼續使用。"
registration: "註冊"
enableRegistration: "開啟新使用者註冊"
invite: "邀請"
@@ -389,8 +389,8 @@ aboutMisskey: "關於 Misskey"
administrator: "管理員"
token: "權杖"
twoStepAuthentication: "兩階段驗證"
-moderator: "審核員"
-moderation: "監察"
+moderator: "審查員"
+moderation: "審查"
nUsersMentioned: "提到了{n}"
securityKey: "安全金鑰"
securityKeyName: "金鑰名稱"
@@ -607,7 +607,7 @@ testEmail: "測試郵件發送"
wordMute: "被靜音的文字"
regexpError: "正規表達式錯誤"
regexpErrorDescription: "{tab} 靜音文字的第 {line} 行的正規表達式有錯誤:"
-instanceMute: "實例的靜音"
+instanceMute: "被靜音的實例"
userSaysSomething: "{name}說了什麼"
makeActive: "啟用"
display: "檢視"
@@ -1181,7 +1181,7 @@ _role:
name: "角色名稱"
description: "角色描述 "
permission: "角色的權限"
- descriptionOfPermission: "<b>審核員</b>執行與審核相關的基本操作。\n<b>管理員</b>能變更實例的全部設定。"
+ descriptionOfPermission: "<b>審查員</b>執行與審查相關的基本操作。\n<b>管理員</b>能變更實例的全部設定"
assignTarget: "指派目標"
descriptionOfAssignTarget: "<b>手動</b>是以手動管理這個角色包含的人員。\n<b>符合條件</b>是設定條件以自動包含符合條件的使用者。"
manual: "手動"
@@ -1198,8 +1198,8 @@ _role:
iconUrl: "圖示的URL"
asBadge: "顯示為徽章"
descriptionOfAsBadge: "開啟的話,角色圖示會顯示在用戶名旁邊。"
- canEditMembersByModerator: "允許編輯監察員的成員"
- descriptionOfCanEditMembersByModerator: "如果開啟,管理員與監察員都可以為使用者指派/解除指派該角色。如果關閉,則只有管理員可以執行。"
+ canEditMembersByModerator: "允許編輯審查員的成員"
+ descriptionOfCanEditMembersByModerator: "如果開啟,管理員與審查員都可以為使用者指派/解除指派該角色。如果關閉,則只有管理員可以執行。"
priority: "優先級"
_priority:
low: "低"
@@ -1236,7 +1236,7 @@ _role:
or: "~或~"
not: "~否"
_sensitiveMediaDetection:
- description: "您可以使用機器學習自動檢測敏感媒體並將其用於審核。 伺服器的負荷會稍微增加。"
+ description: "您可以使用機器學習自動檢測敏感媒體並將其用於審查。 伺服器的負荷會稍微增加。"
sensitivity: "檢測敏感度"
sensitivityDescription: "敏感度低時,誤檢測(偽陽性)會減少。敏感度高時,漏檢(偽陰性)會減少。"
setSensitiveFlagAutomatically: "設定 NSFW 旗標"
diff --git a/package.json b/package.json
index 6e0414ec08..10de772e68 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "misskey",
- "version": "13.4.0",
+ "version": "13.5.0",
"codename": "nasubi",
"repository": {
"type": "git",
@@ -19,7 +19,7 @@
"start": "cd packages/backend && node ./built/boot/index.js",
"start:test": "cd packages/backend && cross-env NODE_ENV=test node ./built/boot/index.js",
"init": "pnpm migrate",
- "migrate": "cd packages/backend && pnpm typeorm migration:run -d ormconfig.js",
+ "migrate": "cd packages/backend && pnpm migrate",
"migrateandstart": "pnpm migrate && pnpm start",
"gulp": "pnpm exec gulp build",
"watch": "pnpm dev",
@@ -28,8 +28,8 @@
"cy:open": "pnpm cypress open --browser --e2e --config-file=cypress.config.ts",
"cy:run": "pnpm cypress run",
"e2e": "pnpm start-server-and-test start:test http://localhost:61812 cy:run",
- "jest": "cd packages/backend && pnpm cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit --runInBand",
- "jest-and-coverage": "cd packages/backend && pnpm cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --coverage --forceExit --runInBand",
+ "jest": "cd packages/backend && pnpm jest",
+ "jest-and-coverage": "cd packages/backend && pnpm jest-and-coverage",
"test": "pnpm jest",
"test-and-coverage": "pnpm jest-and-coverage",
"format": "pnpm exec gulp format",
diff --git a/packages/backend/ormconfig.js b/packages/backend/ormconfig.js
index 32c26f7b67..229e5bf1fe 100644
--- a/packages/backend/ormconfig.js
+++ b/packages/backend/ormconfig.js
@@ -1,6 +1,6 @@
import { DataSource } from 'typeorm';
import { loadConfig } from './built/config.js';
-import { entities } from './built/postgre.js';
+import { entities } from './built/postgres.js';
const config = loadConfig();
diff --git a/packages/backend/src/GlobalModule.ts b/packages/backend/src/GlobalModule.ts
index 8a70129eb9..35416209a0 100644
--- a/packages/backend/src/GlobalModule.ts
+++ b/packages/backend/src/GlobalModule.ts
@@ -4,7 +4,7 @@ import { DataSource } from 'typeorm';
import { createRedisConnection } from '@/redis.js';
import { DI } from './di-symbols.js';
import { loadConfig } from './config.js';
-import { createPostgreDataSource } from './postgre.js';
+import { createPostgresDataSource } from './postgres.js';
import { RepositoryModule } from './models/RepositoryModule.js';
import type { Provider, OnApplicationShutdown } from '@nestjs/common';
@@ -18,7 +18,7 @@ const $config: Provider = {
const $db: Provider = {
provide: DI.db,
useFactory: async (config) => {
- const db = createPostgreDataSource(config);
+ const db = createPostgresDataSource(config);
return await db.initialize();
},
inject: [DI.config],
diff --git a/packages/backend/src/core/CustomEmojiService.ts b/packages/backend/src/core/CustomEmojiService.ts
index 63f0319442..3ac796fb2f 100644
--- a/packages/backend/src/core/CustomEmojiService.ts
+++ b/packages/backend/src/core/CustomEmojiService.ts
@@ -150,17 +150,9 @@ export class CustomEmojiService {
if (note.renote) {
emojis = emojis.concat(note.renote.emojis
.map(e => this.parseEmojiStr(e, note.renote!.userHost)));
- if (note.renote.user) {
- emojis = emojis.concat(note.renote.user.emojis
- .map(e => this.parseEmojiStr(e, note.renote!.userHost)));
- }
}
const customReactions = Object.keys(note.reactions).map(x => this.reactionService.decodeReaction(x)).filter(x => x.name != null) as typeof emojis;
emojis = emojis.concat(customReactions);
- if (note.user) {
- emojis = emojis.concat(note.user.emojis
- .map(e => this.parseEmojiStr(e, note.userHost)));
- }
}
return emojis.filter(x => x.name != null && x.host != null) as { name: string; host: string; }[];
}
diff --git a/packages/backend/src/core/activitypub/models/ApImageService.ts b/packages/backend/src/core/activitypub/models/ApImageService.ts
index d01817b0de..928ef1ae79 100644
--- a/packages/backend/src/core/activitypub/models/ApImageService.ts
+++ b/packages/backend/src/core/activitypub/models/ApImageService.ts
@@ -48,6 +48,10 @@ export class ApImageService {
throw new Error('invalid image: url not privided');
}
+ if (!image.url.startsWith('https://')) {
+ throw new Error('invalid image: unexpected shcema of url: ' + image.url);
+ }
+
this.logger.info(`Creating the Image: ${image.url}`);
const instance = await this.metaService.fetch();
diff --git a/packages/backend/src/core/activitypub/models/ApNoteService.ts b/packages/backend/src/core/activitypub/models/ApNoteService.ts
index c9192f53b7..813415e6f6 100644
--- a/packages/backend/src/core/activitypub/models/ApNoteService.ts
+++ b/packages/backend/src/core/activitypub/models/ApNoteService.ts
@@ -1,8 +1,7 @@
import { forwardRef, Inject, Injectable } from '@nestjs/common';
import promiseLimit from 'promise-limit';
import { DI } from '@/di-symbols.js';
-import type { MessagingMessagesRepository, PollsRepository, EmojisRepository } from '@/models/index.js';
-import type { UsersRepository } from '@/models/index.js';
+import type { MessagingMessagesRepository, PollsRepository, EmojisRepository, UsersRepository } from '@/models/index.js';
import type { Config } from '@/config.js';
import type { CacheableRemoteUser } from '@/models/entities/User.js';
import type { Note } from '@/models/entities/Note.js';
@@ -18,6 +17,7 @@ import { PollService } from '@/core/PollService.js';
import { StatusError } from '@/misc/status-error.js';
import { UtilityService } from '@/core/UtilityService.js';
import { MessagingService } from '@/core/MessagingService.js';
+import { bindThis } from '@/decorators.js';
import { getOneApId, getApId, getOneApHrefNullable, validPost, isEmoji, getApType } from '../type.js';
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
import { ApLoggerService } from '../ApLoggerService.js';
@@ -32,7 +32,6 @@ import { ApQuestionService } from './ApQuestionService.js';
import { ApImageService } from './ApImageService.js';
import type { Resolver } from '../ApResolverService.js';
import type { IObject, IPost } from '../type.js';
-import { bindThis } from '@/decorators.js';
@Injectable()
export class ApNoteService {
@@ -133,6 +132,16 @@ export class ApNoteService {
const note: IPost = object;
this.logger.debug(`Note fetched: ${JSON.stringify(note, null, 2)}`);
+
+ if (note.id && !note.id.startsWith('https://')) {
+ throw new Error('unexpected shcema of note.id: ' + note.id);
+ }
+
+ const url = getOneApHrefNullable(note.url);
+
+ if (url && !url.startsWith('https://')) {
+ throw new Error('unexpected shcema of note url: ' + url);
+ }
this.logger.info(`Creating the Note: ${note.id}`);
@@ -307,7 +316,7 @@ export class ApNoteService {
apEmojis,
poll,
uri: note.id,
- url: getOneApHrefNullable(note.url),
+ url: url,
}, silent);
}
diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts
index 2325bbe093..76f820cda0 100644
--- a/packages/backend/src/core/activitypub/models/ApPersonService.ts
+++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts
@@ -252,6 +252,12 @@ export class ApPersonService implements OnModuleInit {
const bday = person['vcard:bday']?.match(/^\d{4}-\d{2}-\d{2}/);
+ const url = getOneApHrefNullable(person.url);
+
+ if (url && !url.startsWith('https://')) {
+ throw new Error('unexpected shcema of person url: ' + url);
+ }
+
// Create user
let user: IRemoteUser;
try {
@@ -283,7 +289,7 @@ export class ApPersonService implements OnModuleInit {
await transactionalEntityManager.save(new UserProfile({
userId: user.id,
description: person.summary ? this.apMfmService.htmlToMfm(truncate(person.summary, summaryLength), person.tag) : null,
- url: getOneApHrefNullable(person.url),
+ url: url,
fields,
birthday: bday ? bday[0] : null,
location: person['vcard:Address'] ?? null,
@@ -425,6 +431,12 @@ export class ApPersonService implements OnModuleInit {
const bday = person['vcard:bday']?.match(/^\d{4}-\d{2}-\d{2}/);
+ const url = getOneApHrefNullable(person.url);
+
+ if (url && !url.startsWith('https://')) {
+ throw new Error('unexpected shcema of person url: ' + url);
+ }
+
const updates = {
lastFetchedAt: new Date(),
inbox: person.inbox,
@@ -459,7 +471,7 @@ export class ApPersonService implements OnModuleInit {
}
await this.userProfilesRepository.update({ userId: exist.id }, {
- url: getOneApHrefNullable(person.url),
+ url: url,
fields,
description: person.summary ? this.apMfmService.htmlToMfm(truncate(person.summary, summaryLength), person.tag) : null,
birthday: bday ? bday[0] : null,
diff --git a/packages/backend/src/core/entities/DriveFileEntityService.ts b/packages/backend/src/core/entities/DriveFileEntityService.ts
index efc196f74a..9dd115d45a 100644
--- a/packages/backend/src/core/entities/DriveFileEntityService.ts
+++ b/packages/backend/src/core/entities/DriveFileEntityService.ts
@@ -20,6 +20,7 @@ type PackOptions = {
withUser?: boolean,
};
import { bindThis } from '@/decorators.js';
+import { isMimeImage } from '@/misc/is-mime-image.js';
@Injectable()
export class DriveFileEntityService {
@@ -82,7 +83,9 @@ export class DriveFileEntityService {
// リモートかつメディアプロキシ
if (file.uri != null && file.userHost != null && this.config.externalMediaProxyEnabled) {
- return proxiedUrl(file.uri);
+ if (!(mode === 'static' && file.type.startsWith('video'))) {
+ return proxiedUrl(file.uri);
+ }
}
// リモートかつ期限切れはローカルプロキシを試みる
@@ -91,20 +94,19 @@ export class DriveFileEntityService {
if (key && !key.match('/')) { // 古いものはここにオブジェクトストレージキーが入ってるので除外
const url = `${this.config.url}/files/${key}`;
- if (mode === 'avatar') return proxiedUrl(url);
+ if (mode === 'avatar') return proxiedUrl(file.uri);
return url;
}
}
- const isImage = file.type && ['image/png', 'image/apng', 'image/gif', 'image/jpeg', 'image/webp', 'image/avif', 'image/svg+xml'].includes(file.type);
+ const url = file.webpublicUrl ?? file.url;
if (mode === 'static') {
- return file.thumbnailUrl ?? (isImage ? (file.webpublicUrl ?? file.url) : null);
+ return file.thumbnailUrl ?? (isMimeImage(file.type, 'sharp-convertible-image') ? proxiedUrl(url) : null);
+ }
+ if (mode === 'avatar') {
+ return proxiedUrl(url);
}
-
- const url = file.webpublicUrl ?? file.url;
-
- if (mode === 'avatar') return proxiedUrl(url);
return url;
}
diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts
index eea9d5567d..09b69d509a 100644
--- a/packages/backend/src/core/entities/UserEntityService.ts
+++ b/packages/backend/src/core/entities/UserEntityService.ts
@@ -413,7 +413,6 @@ export class UserEntityService implements OnModuleInit {
faviconUrl: instance.faviconUrl,
themeColor: instance.themeColor,
} : undefined) : undefined,
- emojis: this.customEmojiService.populateEmojis(user.emojis, user.host),
onlineStatus: this.getOnlineStatus(user),
// パフォーマンス上の理由でローカルユーザーのみ
badgeRoles: user.host == null ? this.roleService.getUserBadgeRoles(user.id).then(rs => rs.map(r => ({
@@ -464,6 +463,7 @@ export class UserEntityService implements OnModuleInit {
isModerator: role.isModerator,
isAdministrator: role.isAdministrator,
}))),
+ emojis: this.customEmojiService.populateEmojis(user.emojis, user.host),
} : {}),
...(opts.detail && isMe ? {
diff --git a/packages/backend/src/postgre.ts b/packages/backend/src/postgres.ts
index c55cb78a6a..33b924e776 100644
--- a/packages/backend/src/postgre.ts
+++ b/packages/backend/src/postgres.ts
@@ -197,7 +197,7 @@ export const entities = [
const log = process.env.NODE_ENV !== 'production';
-export function createPostgreDataSource(config: Config) {
+export function createPostgresDataSource(config: Config) {
return new DataSource({
type: 'postgres',
host: config.db.host,
diff --git a/packages/backend/test/utils.ts b/packages/backend/test/utils.ts
index c8fd41e1d3..50988939aa 100644
--- a/packages/backend/test/utils.ts
+++ b/packages/backend/test/utils.ts
@@ -11,7 +11,7 @@ import FormData from 'form-data';
import { DataSource } from 'typeorm';
import got, { RequestError } from 'got';
import loadConfig from '../src/config/load.js';
-import { entities } from '../src/postgre.js';
+import { entities } from '@/postgres.js';
import type * as misskey from 'misskey-js';
const _filename = fileURLToPath(import.meta.url);
diff --git a/packages/frontend/src/components/MkAbuseReport.vue b/packages/frontend/src/components/MkAbuseReport.vue
index 0e18a5a83d..701dd8bb3d 100644
--- a/packages/frontend/src/components/MkAbuseReport.vue
+++ b/packages/frontend/src/components/MkAbuseReport.vue
@@ -4,7 +4,7 @@
<MkA v-user-preview="report.targetUserId" class="info" :to="`/user-info/${report.targetUserId}`">
<MkAvatar class="avatar" :user="report.targetUser" indicator/>
<div class="names">
- <MkUserName class="name" :user="report.targetUser"/>
+ <span class="name _nowrap">{{ report.targetUser.name ?? report.targetUser.username }}</span>
<MkAcct class="acct" :user="report.targetUser" style="display: block;"/>
</div>
</MkA>
diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue
index e523b988b0..595e393e01 100644
--- a/packages/frontend/src/components/MkAutocomplete.vue
+++ b/packages/frontend/src/components/MkAutocomplete.vue
@@ -4,7 +4,7 @@
<li v-for="user in users" tabindex="-1" :class="$style.item" @click="complete(type, user)" @keydown="onKeydown">
<img :class="$style.avatar" :src="user.avatarUrl"/>
<span :class="$style.userName">
- <MkUserName :key="user.id" :user="user"/>
+ <span :key="user.id" class="_nowrap">{{ user.name ?? user.username }}</span>
</span>
<span>@{{ acct(user) }}</span>
</li>
diff --git a/packages/frontend/src/components/MkEmojiPicker.vue b/packages/frontend/src/components/MkEmojiPicker.vue
index 2063ab4dec..c7556ec36e 100644
--- a/packages/frontend/src/components/MkEmojiPicker.vue
+++ b/packages/frontend/src/components/MkEmojiPicker.vue
@@ -1,6 +1,6 @@
<template>
<div class="omfetrab" :class="['s' + size, 'w' + width, 'h' + height, { asDrawer, asWindow }]" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : undefined }">
- <input ref="searchEl" :value="q" class="search" data-prevent-emoji-insert :class="{ filled: q != null && q != '' }" :placeholder="i18n.ts.search" type="search" @input="input()" @paste.stop="paste" @keyup.enter="done()">
+ <input ref="searchEl" :value="q" class="search" data-prevent-emoji-insert :class="{ filled: q != null && q != '' }" :placeholder="i18n.ts.search" type="search" @input="input()" @paste.stop="paste" @keydown.stop.prevent.enter="onEnter">
<div ref="emojisEl" class="emojis">
<section class="result">
<div v-if="searchResultCustom.length > 0" class="body">
@@ -327,6 +327,11 @@ function paste(event: ClipboardEvent): void {
}
}
+function onEnter(ev: KeyboardEvent) {
+ if (ev.isComposing || ev.key === 'Process' || ev.keyCode === 229) return;
+ done();
+}
+
function done(query?: string): boolean | void {
if (query == null) query = q.value;
if (query == null || typeof query !== 'string') return;
diff --git a/packages/frontend/src/components/MkMediaBanner.vue b/packages/frontend/src/components/MkMediaBanner.vue
index 718ce80e0d..c4af1ee8d0 100644
--- a/packages/frontend/src/components/MkMediaBanner.vue
+++ b/packages/frontend/src/components/MkMediaBanner.vue
@@ -6,15 +6,14 @@
<span>{{ $ts.clickToShow }}</span>
</div>
<div v-else-if="media.type.startsWith('audio') && media.type !== 'audio/midi'" class="audio">
- <audio
- ref="audioEl"
- class="audio"
- :src="media.url"
- :title="media.name"
- controls
- preload="metadata"
- @volumechange="volumechange"
- />
+ <VuePlyr :options="{ volume: 0.5 }">
+ <audio controls preload="metadata">
+ <source
+ :src="media.url"
+ :type="media.type"
+ />
+ </audio>
+ </VuePlyr>
</div>
<a
v-else class="download"
@@ -31,7 +30,9 @@
<script lang="ts" setup>
import { onMounted } from 'vue';
import * as misskey from 'misskey-js';
+import VuePlyr from 'vue-plyr';
import { ColdDeviceStorage } from '@/store';
+import 'vue-plyr/dist/vue-plyr.css';
const props = withDefaults(defineProps<{
media: misskey.entities.DriveFile;
@@ -55,7 +56,11 @@ onMounted(() => {
width: 100%;
border-radius: 4px;
margin-top: 4px;
- overflow: hidden;
+ overflow: clip;
+
+ --plyr-color-main: var(--accent);
+ --plyr-audio-controls-background: var(--bg);
+ --plyr-audio-controls-color: var(--accentLighten);
> .download,
> .sensitive {
@@ -93,10 +98,8 @@ onMounted(() => {
}
> .audio {
- .audio {
- display: block;
- width: 100%;
- }
+ border-radius: 8px;
+ overflow: clip;
}
}
</style>
diff --git a/packages/frontend/src/components/MkMediaList.vue b/packages/frontend/src/components/MkMediaList.vue
index f263ae0ce9..562cd3d63f 100644
--- a/packages/frontend/src/components/MkMediaList.vue
+++ b/packages/frontend/src/components/MkMediaList.vue
@@ -1,11 +1,11 @@
<template>
-<div class="hoawjimk">
+<div>
<XBanner v-for="media in mediaList.filter(media => !previewable(media))" :key="media.id" :media="media"/>
- <div v-if="mediaList.filter(media => previewable(media)).length > 0" class="gird-container">
- <div ref="gallery" :data-count="mediaList.filter(media => previewable(media)).length">
+ <div v-if="mediaList.filter(media => previewable(media)).length > 0" :class="$style.container">
+ <div ref="gallery" :class="[$style.medias, count <= 4 ? $style['n' + count] : $style.nMany]">
<template v-for="media in mediaList.filter(media => previewable(media))">
- <XVideo v-if="media.type.startsWith('video')" :key="media.id" :video="media"/>
- <XImage v-else-if="media.type.startsWith('image')" :key="media.id" class="image" :data-id="media.id" :image="media" :raw="raw"/>
+ <XVideo v-if="media.type.startsWith('video')" :key="media.id" :class="$style.media" :video="media"/>
+ <XImage v-else-if="media.type.startsWith('image')" :key="media.id" :class="$style.media" class="image" :data-id="media.id" :image="media" :raw="raw"/>
</template>
</div>
</div>
@@ -32,6 +32,7 @@ const props = defineProps<{
const gallery = ref(null);
const pswpZIndex = os.claimZIndex('middle');
+const count = $computed(() => props.mediaList.filter(media => previewable(media)).length);
onMounted(() => {
const lightbox = new PhotoSwipeLightbox({
@@ -122,83 +123,62 @@ const previewable = (file: misskey.entities.DriveFile): boolean => {
};
</script>
-<style lang="scss" scoped>
-.hoawjimk {
- > .gird-container {
- position: relative;
- width: 100%;
- margin-top: 4px;
-
- &:before {
- content: '';
- display: block;
- padding-top: 56.25% // 16:9;
- }
-
- > div {
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- display: grid;
- grid-gap: 8px;
-
- > * {
- overflow: hidden;
- border-radius: 6px;
- }
-
- &[data-count="1"] {
- grid-template-rows: 1fr;
- }
+<style lang="scss" module>
+.container {
+ position: relative;
+ width: 100%;
+ margin-top: 4px;
+}
- &[data-count="2"] {
- grid-template-columns: 1fr 1fr;
- grid-template-rows: 1fr;
- }
+.medias {
+ display: grid;
+ grid-gap: 8px;
- &[data-count="3"] {
- grid-template-columns: 1fr 0.5fr;
- grid-template-rows: 1fr 1fr;
+ &.n1 {
+ aspect-ratio: 16/9;
+ grid-template-rows: 1fr;
+ }
- > *:nth-child(1) {
- grid-row: 1 / 3;
- }
+ &.n2 {
+ aspect-ratio: 16/9;
+ grid-template-columns: 1fr 1fr;
+ grid-template-rows: 1fr;
+ }
- > *:nth-child(3) {
- grid-column: 2 / 3;
- grid-row: 2 / 3;
- }
- }
+ &.n3 {
+ aspect-ratio: 16/9;
+ grid-template-columns: 1fr 0.5fr;
+ grid-template-rows: 1fr 1fr;
- &[data-count="4"] {
- grid-template-columns: 1fr 1fr;
- grid-template-rows: 1fr 1fr;
- }
+ > .media:nth-child(1) {
+ grid-row: 1 / 3;
+ }
- > *:nth-child(1) {
- grid-column: 1 / 2;
- grid-row: 1 / 2;
- }
+ > .media:nth-child(3) {
+ grid-column: 2 / 3;
+ grid-row: 2 / 3;
+ }
+ }
- > *:nth-child(2) {
- grid-column: 2 / 3;
- grid-row: 1 / 2;
- }
+ &.n4 {
+ aspect-ratio: 16/9;
+ grid-template-columns: 1fr 1fr;
+ grid-template-rows: 1fr 1fr;
+ }
- > *:nth-child(3) {
- grid-column: 1 / 2;
- grid-row: 2 / 3;
- }
+ &.nMany {
+ grid-template-columns: 1fr 1fr;
- > *:nth-child(4) {
- grid-column: 2 / 3;
- grid-row: 2 / 3;
- }
+ > .media {
+ aspect-ratio: 16/9;
}
}
}
+
+.media {
+ overflow: hidden; // clipにするとバグる
+ border-radius: 8px;
+}
</style>
<style lang="scss">
diff --git a/packages/frontend/src/components/MkMediaVideo.vue b/packages/frontend/src/components/MkMediaVideo.vue
index 2c24c16f57..979c3eed28 100644
--- a/packages/frontend/src/components/MkMediaVideo.vue
+++ b/packages/frontend/src/components/MkMediaVideo.vue
@@ -6,7 +6,7 @@
</div>
</div>
<div v-else class="kkjnbbplepmiyuadieoenjgutgcmtsvu">
- <vue-plyr>
+ <VuePlyr :options="{ volume: 0.5 }">
<video
controls
:data-poster="video.thumbnailUrl"
@@ -17,7 +17,7 @@
:type="video.type"
/>
</video>
- </vue-plyr>
+ </VuePlyr>
<i class="ti ti-eye-off" @click="hide = true"></i>
</div>
</template>
diff --git a/packages/frontend/src/components/MkMenu.vue b/packages/frontend/src/components/MkMenu.vue
index eee77a9475..2185a3ed08 100644
--- a/packages/frontend/src/components/MkMenu.vue
+++ b/packages/frontend/src/components/MkMenu.vue
@@ -27,7 +27,7 @@
<span v-if="item.indicate" :class="$style.indicator"><i class="_indicatorCircle"></i></span>
</a>
<button v-else-if="item.type === 'user'" :tabindex="i" class="_button" :class="[$style.item, { [$style.active]: item.active }]" :disabled="item.active" @click="clicked(item.action, $event)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
- <MkAvatar :user="item.user" :class="$style.avatar"/><MkUserName :user="item.user"/>
+ <MkAvatar :user="item.user" :class="$style.avatar"/><span class="_nowrap">{{ item.user.name ?? item.user.username }}</span>
<span v-if="item.indicate" :class="$style.indicator"><i class="_indicatorCircle"></i></span>
</button>
<span v-else-if="item.type === 'switch'" :tabindex="i" :class="$style.item" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue
index 351861ac17..a77158c862 100644
--- a/packages/frontend/src/components/MkNote.vue
+++ b/packages/frontend/src/components/MkNote.vue
@@ -17,7 +17,7 @@
<I18n :src="i18n.ts.renotedBy" tag="span" :class="$style.renoteText">
<template #user>
<MkA v-user-preview="note.userId" :class="$style.renoteUserName" :to="userPage(note.user)">
- <MkUserName :user="note.user"/>
+ <span class="_nowrap">{{ note.user.name ?? note.user.username }}</span>
</MkA>
</template>
</I18n>
@@ -108,7 +108,7 @@
<I18n :src="i18n.ts.userSaysSomething" tag="small">
<template #name>
<MkA v-user-preview="appearNote.userId" :to="userPage(appearNote.user)">
- <MkUserName :user="appearNote.user"/>
+ <span class="_nowrap">{{ appearNote.user.name ?? appearNote.user.username }}</span>
</MkA>
</template>
</I18n>
diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue
index 0da06c4f14..b632a77396 100644
--- a/packages/frontend/src/components/MkNoteDetailed.vue
+++ b/packages/frontend/src/components/MkNoteDetailed.vue
@@ -16,7 +16,7 @@
<I18n :src="i18n.ts.renotedBy" tag="span">
<template #user>
<MkA v-user-preview="note.userId" class="name" :to="userPage(note.user)">
- <MkUserName :user="note.user"/>
+ <span class="_nowrap">{{ note.user.name ?? note.user.username }}</span>
</MkA>
</template>
</I18n>
@@ -39,7 +39,7 @@
<div class="body">
<div class="top">
<MkA v-user-preview="appearNote.user.id" class="name" :to="userPage(appearNote.user)">
- <MkUserName :nowrap="false" :user="appearNote.user"/>
+ <span class="_nowrap">{{ appearNote.user.name ?? appearNote.user.username }}</span>
</MkA>
<span v-if="appearNote.user.isBot" class="is-bot">bot</span>
<div class="info">
@@ -125,7 +125,7 @@
<I18n :src="i18n.ts.userSaysSomething" tag="small">
<template #name>
<MkA v-user-preview="appearNote.userId" class="name" :to="userPage(appearNote.user)">
- <MkUserName :user="appearNote.user"/>
+ <span class="_nowrap">{{ appearNote.user.name ?? appearNote.user.username }}</span>
</MkA>
</template>
</I18n>
diff --git a/packages/frontend/src/components/MkNoteHeader.vue b/packages/frontend/src/components/MkNoteHeader.vue
index 6b43f14665..d86a37ed55 100644
--- a/packages/frontend/src/components/MkNoteHeader.vue
+++ b/packages/frontend/src/components/MkNoteHeader.vue
@@ -1,7 +1,7 @@
<template>
<header :class="$style.root">
<MkA v-once v-user-preview="note.user.id" :class="$style.name" :to="userPage(note.user)">
- <MkUserName :user="note.user"/>
+ <span class="_nowrap">{{ note.user.name ?? note.user.username }}</span>
</MkA>
<div v-if="note.user.isBot" :class="$style.isBot">bot</div>
<div :class="$style.username"><MkAcct :user="note.user"/></div>
diff --git a/packages/frontend/src/components/MkNotePreview.vue b/packages/frontend/src/components/MkNotePreview.vue
index 1cc01386ba..d3862e2ac3 100644
--- a/packages/frontend/src/components/MkNotePreview.vue
+++ b/packages/frontend/src/components/MkNotePreview.vue
@@ -3,7 +3,7 @@
<MkAvatar :class="$style.avatar" :user="$i" link preview/>
<div :class="$style.main">
<div :class="$style.header">
- <MkUserName :user="$i"/>
+ <span class="_nowrap">{{ $i.name ?? $i.username }}</span>
</div>
<div>
<div :class="$style.content">
diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue
index e7a951dd27..fd055dfb58 100644
--- a/packages/frontend/src/components/MkNotification.vue
+++ b/packages/frontend/src/components/MkNotification.vue
@@ -31,7 +31,7 @@
<header :class="$style.header">
<span v-if="notification.type === 'pollEnded'">{{ i18n.ts._notification.pollEnded }}</span>
<span v-else-if="notification.type === 'achievementEarned'">{{ i18n.ts._notification.achievementEarned }}</span>
- <MkA v-else-if="notification.user" v-user-preview="notification.user.id" :class="$style.headerName" :to="userPage(notification.user)"><MkUserName :user="notification.user"/></MkA>
+ <MkA v-else-if="notification.user" v-user-preview="notification.user.id" :class="$style.headerName" :to="userPage(notification.user)"><span class="_nowrap">{{ notification.user.name ?? notification.user.username }}</span></MkA>
<span v-else>{{ notification.header }}</span>
<MkTime v-if="withTime" :time="notification.createdAt" :class="$style.headerTime"/>
</header>
diff --git a/packages/frontend/src/components/MkReactionsViewer.details.vue b/packages/frontend/src/components/MkReactionsViewer.details.vue
index b4210be911..b0d7ebf3ee 100644
--- a/packages/frontend/src/components/MkReactionsViewer.details.vue
+++ b/packages/frontend/src/components/MkReactionsViewer.details.vue
@@ -8,7 +8,7 @@
<div :class="$style.users">
<div v-for="u in users" :key="u.id" :class="$style.user">
<MkAvatar :class="$style.avatar" :user="u"/>
- <MkUserName :user="u" :nowrap="true"/>
+ <span class="_nowrap">{{ u.name ?? u.username }}</span>
</div>
<div v-if="users.length > 10">+{{ count - 10 }}</div>
</div>
diff --git a/packages/frontend/src/components/MkUserCardMini.vue b/packages/frontend/src/components/MkUserCardMini.vue
index 457504e6ca..e2b9b2a15f 100644
--- a/packages/frontend/src/components/MkUserCardMini.vue
+++ b/packages/frontend/src/components/MkUserCardMini.vue
@@ -2,7 +2,7 @@
<div v-adaptive-bg :class="[$style.root, { yellow: user.isSilenced, red: user.isSuspended, gray: false }]">
<MkAvatar class="avatar" :user="user" indicator/>
<div class="body">
- <span class="name"><MkUserName class="name" :user="user"/></span>
+ <span class="name _nowrap">{{ user.name ?? user.username }}</span>
<span class="sub"><span class="acct _monospace">@{{ acct(user) }}</span></span>
</div>
<MkMiniChart v-if="chartValues" class="chart" :src="chartValues"/>
diff --git a/packages/frontend/src/components/MkUserInfo.vue b/packages/frontend/src/components/MkUserInfo.vue
index 1486423b3d..4459fd1a5d 100644
--- a/packages/frontend/src/components/MkUserInfo.vue
+++ b/packages/frontend/src/components/MkUserInfo.vue
@@ -3,8 +3,9 @@
<div class="banner" :style="user.bannerUrl ? `background-image: url(${user.bannerUrl})` : ''"></div>
<MkAvatar class="avatar" :user="user" indicator/>
<div class="title">
- <MkA class="name" :to="userPage(user)"><MkUserName :user="user" :nowrap="false"/></MkA>
- <p class="username"><MkAcct :user="user"/></p>
+ <MkA class="name _nowrap" :to="userPage(user)"{{ user.name ?? user.username }}</mk-a>
+ <p class="username"><MkAcct :user="user"/></p>
+ </mka>
</div>
<span v-if="$i && $i.id !== user.id && user.isFollowed" class="followed">{{ $ts.followsYou }}</span>
<div class="description">
diff --git a/packages/frontend/src/components/MkUserPreview.vue b/packages/frontend/src/components/MkUserPreview.vue
index f68fdd64d9..c9519a29a5 100644
--- a/packages/frontend/src/components/MkUserPreview.vue
+++ b/packages/frontend/src/components/MkUserPreview.vue
@@ -7,7 +7,7 @@
</div>
<MkAvatar class="avatar" :user="user" indicator/>
<div class="title">
- <MkA class="name" :to="userPage(user)"><MkUserName :user="user" :nowrap="false"/></MkA>
+ <MkA class="name _nowrap" :to="userPage(user)">{{ user.name ?? user.username }}</MkA>
<p class="username"><MkAcct :user="user"/></p>
</div>
<div class="description">
diff --git a/packages/frontend/src/components/MkUserSelectDialog.vue b/packages/frontend/src/components/MkUserSelectDialog.vue
index c17b97f283..dd976a4b35 100644
--- a/packages/frontend/src/components/MkUserSelectDialog.vue
+++ b/packages/frontend/src/components/MkUserSelectDialog.vue
@@ -27,7 +27,7 @@
<div v-for="user in users" :key="user.id" class="_button" :class="[$style.user, { [$style.selected]: selected && selected.id === user.id }]" @click="selected = user" @dblclick="ok()">
<MkAvatar :user="user" :class="$style.avatar" indicator/>
<div :class="$style.userBody">
- <MkUserName :user="user" :class="$style.userName"/>
+ <span :class="$style.userName" class="_nowrap">{{ user.name ?? user.username }}</span>
<MkAcct :user="user" :class="$style.userAcct"/>
</div>
</div>
@@ -41,7 +41,7 @@
<div v-for="user in recentUsers" :key="user.id" class="_button" :class="[$style.user, { [$style.selected]: selected && selected.id === user.id }]" @click="selected = user" @dblclick="ok()">
<MkAvatar :user="user" :class="$style.avatar" indicator/>
<div :class="$style.userBody">
- <MkUserName :user="user" :class="$style.userName"/>
+ <span :class="$style.userName" class="_nowrap">{{ user.name ?? user.username }}</span>
<MkAcct :user="user" :class="$style.userAcct"/>
</div>
</div>
diff --git a/packages/frontend/src/components/MkUsersTooltip.vue b/packages/frontend/src/components/MkUsersTooltip.vue
index d0f95fceda..c2c7271fcd 100644
--- a/packages/frontend/src/components/MkUsersTooltip.vue
+++ b/packages/frontend/src/components/MkUsersTooltip.vue
@@ -3,7 +3,7 @@
<div :class="$style.root">
<div v-for="u in users" :key="u.id" :class="$style.user">
<MkAvatar :class="$style.avatar" :user="u"/>
- <MkUserName :class="$style.name" :user="u" :nowrap="true"/>
+ <span :class="$style.name" class="_nowrap">{{ u.name ?? u.username }}</span>
</div>
<div v-if="users.length < count" :class="$style.omitted">+{{ count - users.length }}</div>
</div>
diff --git a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.vue b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.vue
index 28a0d1c986..f49dc7ddff 100644
--- a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.vue
+++ b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.vue
@@ -1,5 +1,5 @@
<template>
-<MfmCore :text="text" :plain="plain" :nowrap="nowrap" :author="author" :is-note="isNote" :class="[$style.root, { [$style.nowrap]: nowrap }]"/>
+<MfmCore :text="text" :plain="plain" :nowrap="nowrap" :author="author" :is-note="isNote" :class="[$style.root, { '_nowrap': nowrap }]"/>
</template>
<script lang="ts" setup>
@@ -160,12 +160,5 @@ const props = withDefaults(defineProps<{
<style lang="scss" module>
.root {
white-space: pre-wrap;
-
- &.nowrap {
- white-space: pre;
- word-wrap: normal; // https://codeday.me/jp/qa/20190424/690106.html
- overflow: hidden;
- text-overflow: ellipsis;
- }
}
</style>
diff --git a/packages/frontend/src/components/global/MkPageHeader.vue b/packages/frontend/src/components/global/MkPageHeader.vue
index ab66502e06..3dcb19bd89 100644
--- a/packages/frontend/src/components/global/MkPageHeader.vue
+++ b/packages/frontend/src/components/global/MkPageHeader.vue
@@ -9,7 +9,7 @@
<i v-else-if="metadata.icon" :class="[$style.titleIcon, metadata.icon]"></i>
<div :class="$style.title">
- <MkUserName v-if="metadata.userName" :user="metadata.userName" :nowrap="true"/>
+ <span v-if="metadata.userName" class="_nowrap">{{ metadata.userName.name ?? metadata.userName.username }}</span>
<div v-else-if="metadata.title">{{ metadata.title }}</div>
<div v-if="!narrow && metadata.subtitle" :class="$style.subtitle">
{{ metadata.subtitle }}
diff --git a/packages/frontend/src/components/global/MkUserName.vue b/packages/frontend/src/components/global/MkUserName.vue
deleted file mode 100644
index 4186a4a4fb..0000000000
--- a/packages/frontend/src/components/global/MkUserName.vue
+++ /dev/null
@@ -1,15 +0,0 @@
-<template>
-<Mfm :text="user.name ?? user.username" :author="user" :plain="true" :nowrap="nowrap" :emoji-urls="user.emojis"/>
-</template>
-
-<script lang="ts" setup>
-import { } from 'vue';
-import * as misskey from 'misskey-js';
-
-const props = withDefaults(defineProps<{
- user: misskey.entities.User;
- nowrap?: boolean;
-}>(), {
- nowrap: true,
-});
-</script>
diff --git a/packages/frontend/src/components/index.ts b/packages/frontend/src/components/index.ts
index 560870f84c..4ddebe7827 100644
--- a/packages/frontend/src/components/index.ts
+++ b/packages/frontend/src/components/index.ts
@@ -6,7 +6,6 @@ import MkAcct from './global/MkAcct.vue';
import MkAvatar from './global/MkAvatar.vue';
import MkEmoji from './global/MkEmoji.vue';
import MkCustomEmoji from './global/MkCustomEmoji.vue';
-import MkUserName from './global/MkUserName.vue';
import MkEllipsis from './global/MkEllipsis.vue';
import MkTime from './global/MkTime.vue';
import MkUrl from './global/MkUrl.vue';
@@ -28,7 +27,6 @@ export default function(app: App) {
app.component('MkAvatar', MkAvatar);
app.component('MkEmoji', MkEmoji);
app.component('MkCustomEmoji', MkCustomEmoji);
- app.component('MkUserName', MkUserName);
app.component('MkEllipsis', MkEllipsis);
app.component('MkTime', MkTime);
app.component('MkUrl', MkUrl);
@@ -50,7 +48,6 @@ declare module '@vue/runtime-core' {
MkAvatar: typeof MkAvatar;
MkEmoji: typeof MkEmoji;
MkCustomEmoji: typeof MkCustomEmoji;
- MkUserName: typeof MkUserName;
MkEllipsis: typeof MkEllipsis;
MkTime: typeof MkTime;
MkUrl: typeof MkUrl;
diff --git a/packages/frontend/src/components/mfm.ts b/packages/frontend/src/components/mfm.ts
index 7cfb19aeb6..683c9014a1 100644
--- a/packages/frontend/src/components/mfm.ts
+++ b/packages/frontend/src/components/mfm.ts
@@ -195,7 +195,7 @@ export default defineComponent({
return h(MkSparkle, {}, genEl(token.children));
}
case 'rotate': {
- const degrees = parseFloat(token.props.args.deg) ?? '90';
+ const degrees = parseFloat(token.props.args.deg ?? '90');
style = `transform: rotate(${degrees}deg); transform-origin: center center;`;
break;
}
diff --git a/packages/frontend/src/pages/clip.vue b/packages/frontend/src/pages/clip.vue
index cd9cec0d4f..89419f79cb 100644
--- a/packages/frontend/src/pages/clip.vue
+++ b/packages/frontend/src/pages/clip.vue
@@ -8,7 +8,7 @@
<Mfm :text="clip.description" :is-note="false" :i="$i"/>
</div>
<div class="user">
- <MkAvatar :user="clip.user" class="avatar" indicator link preview/> <MkUserName :user="clip.user" :nowrap="false"/>
+ <MkAvatar :user="clip.user" class="avatar" indicator link preview/> <span class="_nowrap">{{ clip.user.name ?? clip.user.username }}</span>
</div>
</div>
diff --git a/packages/frontend/src/pages/follow-requests.vue b/packages/frontend/src/pages/follow-requests.vue
index 835dd0b54c..e8a59d71e0 100644
--- a/packages/frontend/src/pages/follow-requests.vue
+++ b/packages/frontend/src/pages/follow-requests.vue
@@ -15,7 +15,7 @@
<MkAvatar class="avatar" :user="req.follower" indicator link preview/>
<div class="body">
<div class="name">
- <MkA v-user-preview="req.follower.id" class="name" :to="userPage(req.follower)"><MkUserName :user="req.follower"/></MkA>
+ <MkA v-user-preview="req.follower.id" class="name _nowrap" :to="userPage(req.follower)">{{ req.follower.name ?? req.follower.username }}</MkA>
<p class="acct">@{{ acct(req.follower) }}</p>
</div>
<div v-if="req.follower.description" class="description" :title="req.follower.description">
diff --git a/packages/frontend/src/pages/gallery/post.vue b/packages/frontend/src/pages/gallery/post.vue
index 31e2727bb5..20bc0e3d39 100644
--- a/packages/frontend/src/pages/gallery/post.vue
+++ b/packages/frontend/src/pages/gallery/post.vue
@@ -30,7 +30,7 @@
<div class="user">
<MkAvatar :user="post.user" class="avatar" link preview/>
<div class="name">
- <MkUserName :user="post.user" style="display: block;"/>
+ <div class="_nowrap">{{ post.user.name ?? post.user.username }}</div>
<MkAcct :user="post.user"/>
</div>
<MkFollowButton v-if="!$i || $i.id != post.user.id" :user="post.user" :inline="true" :transparent="false" :full="true" large class="koudoku"/>
diff --git a/packages/frontend/src/pages/messaging/index.vue b/packages/frontend/src/pages/messaging/index.vue
index 3d11cf13e9..0fd1f71d42 100644
--- a/packages/frontend/src/pages/messaging/index.vue
+++ b/packages/frontend/src/pages/messaging/index.vue
@@ -22,7 +22,7 @@
<MkTime :time="message.createdAt" class="time"/>
</header>
<header v-else>
- <span class="name"><MkUserName :user="isMe(message) ? message.recipient : message.user"/></span>
+ <span class="name">{{ isMe(message) ? message.recipient.name : message.user.name }}</span>
<span class="username">@{{ acct(isMe(message) ? message.recipient : message.user) }}</span>
<MkTime :time="message.createdAt" class="time"/>
</header>
diff --git a/packages/frontend/src/pages/my-lists/list.vue b/packages/frontend/src/pages/my-lists/list.vue
index f47b4bf90f..cb190fb112 100644
--- a/packages/frontend/src/pages/my-lists/list.vue
+++ b/packages/frontend/src/pages/my-lists/list.vue
@@ -21,7 +21,7 @@
<div v-for="user in users" :key="user.id" class="user _panel">
<MkAvatar :user="user" class="avatar" indicator link preview/>
<div class="body">
- <MkUserName :user="user" class="name"/>
+ <span class="name _nowrap">{{ user.name ?? user.username }}</span>
<MkAcct :user="user" class="acct"/>
</div>
<div class="action">
diff --git a/packages/frontend/src/pages/note.vue b/packages/frontend/src/pages/note.vue
index 86b3fce3c5..e28c30f627 100644
--- a/packages/frontend/src/pages/note.vue
+++ b/packages/frontend/src/pages/note.vue
@@ -21,7 +21,7 @@
<b>{{ item.name }}</b>
<div v-if="item.description" class="description">{{ item.description }}</div>
<div class="user">
- <MkAvatar :user="item.user" class="avatar" indicator link preview/> <MkUserName :user="item.user" :nowrap="false"/>
+ <MkAvatar :user="item.user" class="avatar" indicator link preview/> <span class="_nowrap">{{ item.user.name ?? item.user.username }}</span>
</div>
</MkA>
</div>
diff --git a/packages/frontend/src/pages/page.vue b/packages/frontend/src/pages/page.vue
index 202244b34c..a4bc17e3bf 100644
--- a/packages/frontend/src/pages/page.vue
+++ b/packages/frontend/src/pages/page.vue
@@ -29,7 +29,7 @@
<div class="user">
<MkAvatar :user="page.user" class="avatar" link preview/>
<div class="name">
- <MkUserName :user="page.user" style="display: block;"/>
+ <div class="_nowrap">{{ page.user.name ?? page.user.username }}</div>
<MkAcct :user="page.user"/>
</div>
<MkFollowButton v-if="!$i || $i.id != page.user.id" :user="page.user" :inline="true" :transparent="false" :full="true" large class="koudoku"/>
diff --git a/packages/frontend/src/pages/settings/accounts.vue b/packages/frontend/src/pages/settings/accounts.vue
index a5eaae2bad..8fa30bccba 100644
--- a/packages/frontend/src/pages/settings/accounts.vue
+++ b/packages/frontend/src/pages/settings/accounts.vue
@@ -9,9 +9,7 @@
<MkAvatar :user="account" class="avatar"/>
</div>
<div class="body">
- <div class="name">
- <MkUserName :user="account"/>
- </div>
+ <div class="name _nowrap">{{ account.name ?? account.username }}</div>
<div class="acct">
<MkAcct :user="account"/>
</div>
diff --git a/packages/frontend/src/pages/user-info.vue b/packages/frontend/src/pages/user-info.vue
index 7ba8a3d16b..40e5ec83c9 100644
--- a/packages/frontend/src/pages/user-info.vue
+++ b/packages/frontend/src/pages/user-info.vue
@@ -7,7 +7,7 @@
<div class="aeakzknw">
<MkAvatar class="avatar" :user="user" indicator link preview/>
<div class="body">
- <span class="name"><MkUserName class="name" :user="user"/></span>
+ <span class="name _nowrap">{{ user.name ?? user.username }}</span>
<span class="sub"><span class="acct _monospace">@{{ acct(user) }}</span></span>
<span class="state">
<span v-if="suspended" class="suspended">Suspended</span>
diff --git a/packages/frontend/src/pages/user/home.vue b/packages/frontend/src/pages/user/home.vue
index 56858a9377..e4bb024a83 100644
--- a/packages/frontend/src/pages/user/home.vue
+++ b/packages/frontend/src/pages/user/home.vue
@@ -14,7 +14,7 @@
<div ref="bannerEl" class="banner" :style="style"></div>
<div class="fade"></div>
<div class="title">
- <MkUserName class="name" :user="user" :nowrap="true"/>
+ <span class="name _nowrap">{{ user.name ?? user.username }}</span>
<div class="bottom">
<span class="username"><MkAcct :user="user" :detail="true"/></span>
<span v-if="user.isAdmin" :title="i18n.ts.isAdmin" style="color: var(--badge);"><i class="ti ti-shield"></i></span>
@@ -30,7 +30,7 @@
</div>
<MkAvatar class="avatar" :user="user" indicator/>
<div class="title">
- <MkUserName :user="user" :nowrap="false" class="name"/>
+ <span class="name _nowrap">{{ user.name ?? user.username }}</span>
<div class="bottom">
<span class="username"><MkAcct :user="user" :detail="true"/></span>
<span v-if="user.isAdmin" :title="i18n.ts.isAdmin" style="color: var(--badge);"><i class="ti ti-shield"></i></span>
diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts
index 8ecf59edb2..94892ff526 100644
--- a/packages/frontend/src/store.ts
+++ b/packages/frontend/src/store.ts
@@ -168,7 +168,7 @@ export const defaultStore = markRaw(new Storage('base', {
},
disableShowingAnimatedImages: {
where: 'device',
- default: false,
+ default: matchMedia('(prefers-reduced-motion)').matches,
},
emojiStyle: {
where: 'device',
diff --git a/packages/frontend/src/style.scss b/packages/frontend/src/style.scss
index aa4efe3052..bacdc967d8 100644
--- a/packages/frontend/src/style.scss
+++ b/packages/frontend/src/style.scss
@@ -156,6 +156,13 @@ hr {
-webkit-touch-callout: none;
}
+._nowrap {
+ white-space: pre;
+ word-wrap: normal; // https://codeday.me/jp/qa/20190424/690106.html
+ overflow: clip;
+ text-overflow: ellipsis;
+}
+
._ghost {
@extend ._noSelect;
pointer-events: none;
diff --git a/packages/frontend/src/widgets/WidgetProfile.vue b/packages/frontend/src/widgets/WidgetProfile.vue
index 7e8ac429e5..b2a5c87104 100644
--- a/packages/frontend/src/widgets/WidgetProfile.vue
+++ b/packages/frontend/src/widgets/WidgetProfile.vue
@@ -6,9 +6,7 @@
</div>
<div :class="$style.bodyContainer">
<div :class="$style.body">
- <MkA :class="$style.name" :to="userPage($i)">
- <MkUserName :user="$i"/>
- </MkA>
+ <MkA :class="$style.name" :to="userPage($i)" class="_nowrap">{{ $i.name ?? $i.username }}</MkA>
<div :class="$style.username"><MkAcct :user="$i" detail/></div>
</div>
</div>