Merge branch 'develop' into 'refactor/kernel-index-cc'
# Conflicts: # packages/backend/src/remote/activitypub/kernel/index.ts
3
.gitignore
vendored
|
@ -32,6 +32,9 @@ coverage
|
||||||
# docker dev config
|
# docker dev config
|
||||||
/dev/docker-compose.yml
|
/dev/docker-compose.yml
|
||||||
|
|
||||||
|
# ESLint
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
# misskey
|
# misskey
|
||||||
built
|
built
|
||||||
db
|
db
|
||||||
|
|
16
.vscode/extensions.json
vendored
|
@ -1,10 +1,18 @@
|
||||||
{
|
{
|
||||||
"recommendations": [
|
"recommendations": [
|
||||||
"editorconfig.editorconfig",
|
"editorconfig.editorconfig",
|
||||||
"rome.rome",
|
"vue.volar",
|
||||||
"Vue.volar",
|
"vue.vscode-typescript-vue-plugin",
|
||||||
"Vue.vscode-typescript-vue-plugin",
|
|
||||||
"arcanis.vscode-zipfs",
|
"arcanis.vscode-zipfs",
|
||||||
"Orta.vscode-twoslash-queries"
|
"orta.vscode-twoslash-queries",
|
||||||
|
"antfu.iconify",
|
||||||
|
"vivaxy.vscode-conventional-commits",
|
||||||
|
"ms-azuretools.vscode-docker",
|
||||||
|
"gitlab.gitlab-workflow",
|
||||||
|
"mrmlnc.vscode-json5",
|
||||||
|
"esbenp.prettier-vscode",
|
||||||
|
"redhat.vscode-yaml",
|
||||||
|
"yoavbls.pretty-ts-errors",
|
||||||
|
"biomejs.biome"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,7 @@ If you have access to a server that supports one of the sources below, I recomme
|
||||||
|
|
||||||
- 🐢 At least [NodeJS](https://nodejs.org/en/) v18.16.0 (v20 recommended)
|
- 🐢 At least [NodeJS](https://nodejs.org/en/) v18.16.0 (v20 recommended)
|
||||||
- 🐘 At least [PostgreSQL](https://www.postgresql.org/) v12 (v14 recommended)
|
- 🐘 At least [PostgreSQL](https://www.postgresql.org/) v12 (v14 recommended)
|
||||||
- 🍱 At least [Redis](https://redis.io/) v6 (v7 recommended)
|
- 🍱 At least [Redis](https://redis.io/) v7
|
||||||
- Web Proxy (one of the following)
|
- Web Proxy (one of the following)
|
||||||
- 🍀 Nginx (recommended)
|
- 🍀 Nginx (recommended)
|
||||||
- 🦦 Caddy
|
- 🦦 Caddy
|
||||||
|
|
12
biome.json
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://biomejs.dev/schemas/1.0.0/schema.json",
|
||||||
|
"organizeImports": {
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"linter": {
|
||||||
|
"enabled": true,
|
||||||
|
"rules": {
|
||||||
|
"recommended": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,6 +61,8 @@ services:
|
||||||
# sonic:
|
# sonic:
|
||||||
# restart: unless-stopped
|
# restart: unless-stopped
|
||||||
# image: docker.io/valeriansaliou/sonic:v1.4.0
|
# image: docker.io/valeriansaliou/sonic:v1.4.0
|
||||||
|
# logging:
|
||||||
|
# driver: none
|
||||||
# networks:
|
# networks:
|
||||||
# - calcnet
|
# - calcnet
|
||||||
# volumes:
|
# volumes:
|
||||||
|
|
|
@ -71,7 +71,7 @@ driveFileDeleteConfirm: "Êtes-vous sûr·e de vouloir supprimer le fichier \"{n
|
||||||
\ ? Il sera retiré de toutes les publications qui le contiennent comme pièce-jointe."
|
\ ? Il sera retiré de toutes les publications qui le contiennent comme pièce-jointe."
|
||||||
unfollowConfirm: "Désirez-vous vous désabonner de {name} ?"
|
unfollowConfirm: "Désirez-vous vous désabonner de {name} ?"
|
||||||
exportRequested: "Vous avez demandé une exportation. L’opération pourrait prendre
|
exportRequested: "Vous avez demandé une exportation. L’opération pourrait prendre
|
||||||
un peu de temps. Une terminée, le fichier résultant sera ajouté au Drive."
|
un peu de temps. Une fois terminée, le fichier résultant sera ajouté au Drive."
|
||||||
importRequested: "Vous avez initié un import. Cela pourrait prendre un peu de temps."
|
importRequested: "Vous avez initié un import. Cela pourrait prendre un peu de temps."
|
||||||
lists: "Listes"
|
lists: "Listes"
|
||||||
noLists: "Vous n’avez aucune liste"
|
noLists: "Vous n’avez aucune liste"
|
||||||
|
|
|
@ -74,7 +74,7 @@ exportRequested: "Kamu telah meminta ekspor. Ini akan memakan waktu sesaat. Sete
|
||||||
importRequested: "Kamu telah meminta impor. Ini akan memakan waktu sesaat."
|
importRequested: "Kamu telah meminta impor. Ini akan memakan waktu sesaat."
|
||||||
lists: "Daftar"
|
lists: "Daftar"
|
||||||
noLists: "Kamu tidak memiliki daftar apapun"
|
noLists: "Kamu tidak memiliki daftar apapun"
|
||||||
note: "Postingan"
|
note: "Posting"
|
||||||
notes: "Postingan"
|
notes: "Postingan"
|
||||||
following: "Ikuti"
|
following: "Ikuti"
|
||||||
followers: "Pengikut"
|
followers: "Pengikut"
|
||||||
|
@ -1837,7 +1837,7 @@ _notification:
|
||||||
followBack: "Ikuti Kembali"
|
followBack: "Ikuti Kembali"
|
||||||
reply: "Balas"
|
reply: "Balas"
|
||||||
renote: "Posting ulang"
|
renote: "Posting ulang"
|
||||||
reacted: berekasi ke postinganmu
|
reacted: mereaksi postinganmu
|
||||||
renoted: memposting ulang postinganmu
|
renoted: memposting ulang postinganmu
|
||||||
voted: memilih di angketmu
|
voted: memilih di angketmu
|
||||||
_deck:
|
_deck:
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
_lang_: "한국어"
|
_lang_: "한국어"
|
||||||
headlineFirefish: "노트로 연결되는 네트워크"
|
headlineFirefish: "영원히 무료로 제공되는 오픈 소스 탈중앙화 소셜 미디어 플랫폼 🚀"
|
||||||
introFirefish: "환영합니다! Firefish 는 오픈 소스 분산형 마이크로 블로그 서비스입니다.\n\"노트\" 를 작성해서, 지금 일어나고
|
introFirefish: "환영합니다! Firefish 는 영원히 무료로 제공되는 오픈 소스 분산형 소셜 미디어 플랫폼입니다! 🚀"
|
||||||
있는 일을 공유하거나, 당신만의 이야기를 모두에게 발신하세요📡\n\"리액션\" 기능으로, 친구의 노트에 총알같이 반응을 추가할 수도 있습니다👍\n
|
|
||||||
새로운 세계를 탐험해 보세요🚀"
|
|
||||||
monthAndDay: "{month}월 {day}일"
|
monthAndDay: "{month}월 {day}일"
|
||||||
search: "검색"
|
search: "검색"
|
||||||
notifications: "알림"
|
notifications: "알림"
|
||||||
|
@ -14,8 +12,8 @@ ok: "OK"
|
||||||
gotIt: "알겠어요"
|
gotIt: "알겠어요"
|
||||||
cancel: "취소"
|
cancel: "취소"
|
||||||
enterUsername: "유저명 입력"
|
enterUsername: "유저명 입력"
|
||||||
renotedBy: "{user}님이 Renote"
|
renotedBy: "{user}님이 부스트"
|
||||||
noNotes: "노트가 없습니다"
|
noNotes: "게시물이 없습니다"
|
||||||
noNotifications: "표시할 알림이 없습니다"
|
noNotifications: "표시할 알림이 없습니다"
|
||||||
instance: "서버"
|
instance: "서버"
|
||||||
settings: "설정"
|
settings: "설정"
|
||||||
|
@ -45,7 +43,7 @@ copyContent: "내용 복사"
|
||||||
copyLink: "링크 복사"
|
copyLink: "링크 복사"
|
||||||
delete: "삭제"
|
delete: "삭제"
|
||||||
deleteAndEdit: "삭제 후 편집"
|
deleteAndEdit: "삭제 후 편집"
|
||||||
deleteAndEditConfirm: "이 노트를 삭제한 뒤 다시 편집하시겠습니까? 이 노트에 대한 리액션, 리노트, 답글 또한 모두 삭제됩니다."
|
deleteAndEditConfirm: "이 게시물을 삭제한 뒤 다시 편집하시겠습니까? 이 게시물에 대한 리액션, 부스트, 답글 또한 모두 삭제됩니다."
|
||||||
addToList: "리스트에 추가"
|
addToList: "리스트에 추가"
|
||||||
sendMessage: "메시지 보내기"
|
sendMessage: "메시지 보내기"
|
||||||
copyUsername: "유저명 복사"
|
copyUsername: "유저명 복사"
|
||||||
|
@ -59,20 +57,20 @@ receiveFollowRequest: "새로운 팔로우 요청이 있습니다"
|
||||||
followRequestAccepted: "팔로우가 수락되었습니다"
|
followRequestAccepted: "팔로우가 수락되었습니다"
|
||||||
mention: "멘션"
|
mention: "멘션"
|
||||||
mentions: "받은 멘션"
|
mentions: "받은 멘션"
|
||||||
directNotes: "다이렉트 노트"
|
directNotes: "다이렉트 게시물"
|
||||||
importAndExport: "가져오기와 내보내기"
|
importAndExport: "가져오기와 내보내기"
|
||||||
import: "가져오기"
|
import: "가져오기"
|
||||||
export: "내보내기"
|
export: "내보내기"
|
||||||
files: "파일"
|
files: "파일"
|
||||||
download: "다운로드"
|
download: "다운로드"
|
||||||
driveFileDeleteConfirm: "파일 \"{name}\" 을 삭제하시겠습니까? 이 파일이 첨부되었더 노트에서도 같이 삭제됩니다."
|
driveFileDeleteConfirm: "파일 \"{name}\" 을 삭제하시겠습니까? 이 파일이 첨부되었더 게시물에서도 같이 삭제됩니다."
|
||||||
unfollowConfirm: "{name}님을 언팔로우하시겠습니까?"
|
unfollowConfirm: "{name}님을 언팔로우하시겠습니까?"
|
||||||
exportRequested: "내보내기를 요청하였습니다. 이 작업은 시간이 걸릴 수 있습니다. 내보내기가 완료되면 \"드라이브\"에 추가됩니다."
|
exportRequested: "내보내기를 요청하였습니다. 이 작업은 시간이 걸릴 수 있습니다. 내보내기가 완료되면 \"드라이브\"에 추가됩니다."
|
||||||
importRequested: "가져오기를 요청하였습니다. 이 작업에는 시간이 걸릴 수 있습니다."
|
importRequested: "가져오기를 요청하였습니다. 이 작업에는 시간이 걸릴 수 있습니다."
|
||||||
lists: "리스트"
|
lists: "리스트"
|
||||||
noLists: "리스트가 없습니다"
|
noLists: "리스트가 없습니다"
|
||||||
note: "노트"
|
note: "게시"
|
||||||
notes: "노트"
|
notes: "게시물"
|
||||||
following: "팔로잉"
|
following: "팔로잉"
|
||||||
followers: "팔로워"
|
followers: "팔로워"
|
||||||
followsYou: "당신을 팔로우합니다"
|
followsYou: "당신을 팔로우합니다"
|
||||||
|
@ -96,13 +94,13 @@ followRequests: "팔로우 요청"
|
||||||
unfollow: "팔로우 해제"
|
unfollow: "팔로우 해제"
|
||||||
followRequestPending: "팔로우 허가 대기중"
|
followRequestPending: "팔로우 허가 대기중"
|
||||||
enterEmoji: "이모지 입력"
|
enterEmoji: "이모지 입력"
|
||||||
renote: "Renote"
|
renote: "부스트"
|
||||||
unrenote: "Renote 취소"
|
unrenote: "부스트 취소"
|
||||||
renoted: "Renote 하였습니다"
|
renoted: "부스트 하였습니다"
|
||||||
cantRenote: "이 게시물은 Renote할 수 없습니다."
|
cantRenote: "이 게시물은 부스트할 수 없습니다."
|
||||||
cantReRenote: "Renote를 Renote할 수 없습니다."
|
cantReRenote: "부스트를 부스트할 수 없습니다."
|
||||||
quote: "인용"
|
quote: "인용"
|
||||||
pinnedNote: "고정해놓은 노트"
|
pinnedNote: "고정해놓은 게시물"
|
||||||
pinned: "프로필에 고정"
|
pinned: "프로필에 고정"
|
||||||
you: "당신"
|
you: "당신"
|
||||||
clickToShow: "클릭하여 보기"
|
clickToShow: "클릭하여 보기"
|
||||||
|
@ -146,7 +144,7 @@ flagAsBotDescription: "이 계정을 자동화된 수단으로 운용할 경우
|
||||||
봇 끼리의 무한 연쇄 반응을 회피하거나, 이 계정의 시스템 상에서의 취급이 Bot 운영에 최적화되는 등의 변화가 생깁니다."
|
봇 끼리의 무한 연쇄 반응을 회피하거나, 이 계정의 시스템 상에서의 취급이 Bot 운영에 최적화되는 등의 변화가 생깁니다."
|
||||||
flagAsCat: "나는 고양이다냥"
|
flagAsCat: "나는 고양이다냥"
|
||||||
flagAsCatDescription: "이 계정이 고양이라면 활성화 해주세요."
|
flagAsCatDescription: "이 계정이 고양이라면 활성화 해주세요."
|
||||||
flagShowTimelineReplies: "타임라인에 노트의 답글을 표시하기"
|
flagShowTimelineReplies: "타임라인에 게시물의 답글을 표시하기"
|
||||||
flagShowTimelineRepliesDescription: "이 설정을 활성화하면 타임라인에 다른 유저 간의 답글을 표시합니다."
|
flagShowTimelineRepliesDescription: "이 설정을 활성화하면 타임라인에 다른 유저 간의 답글을 표시합니다."
|
||||||
autoAcceptFollowed: "팔로우 중인 유저로부터의 팔로우 요청을 자동 수락"
|
autoAcceptFollowed: "팔로우 중인 유저로부터의 팔로우 요청을 자동 수락"
|
||||||
addAccount: "계정 추가"
|
addAccount: "계정 추가"
|
||||||
|
@ -205,7 +203,7 @@ noUsers: "아무도 없습니다"
|
||||||
editProfile: "프로필 수정"
|
editProfile: "프로필 수정"
|
||||||
noteDeleteConfirm: "이 게시물을 삭제하시겠습니까?"
|
noteDeleteConfirm: "이 게시물을 삭제하시겠습니까?"
|
||||||
pinLimitExceeded: "더 이상 고정할 수 없습니다."
|
pinLimitExceeded: "더 이상 고정할 수 없습니다."
|
||||||
intro: "Misskey의 설치가 완료되었습니다! 관리자 계정을 생성해주세요."
|
intro: "Firefish의 설치가 완료되었습니다! 관리자 계정을 생성해주세요."
|
||||||
done: "완료"
|
done: "완료"
|
||||||
processing: "처리중"
|
processing: "처리중"
|
||||||
preview: "미리보기"
|
preview: "미리보기"
|
||||||
|
@ -294,7 +292,7 @@ emptyDrive: "드라이브가 비어 있습니다"
|
||||||
emptyFolder: "폴더가 비어 있습니다"
|
emptyFolder: "폴더가 비어 있습니다"
|
||||||
unableToDelete: "삭제할 수 없습니다"
|
unableToDelete: "삭제할 수 없습니다"
|
||||||
inputNewFileName: "바꿀 파일명을 입력해 주세요"
|
inputNewFileName: "바꿀 파일명을 입력해 주세요"
|
||||||
inputNewDescription: "새 캡션을 입력해 주세요"
|
inputNewDescription: "새 설명을 입력해 주세요"
|
||||||
inputNewFolderName: "바꿀 폴더명을 입력해 주세요"
|
inputNewFolderName: "바꿀 폴더명을 입력해 주세요"
|
||||||
circularReferenceFolder: "지정한 폴더가 이동할 폴더의 하위 폴더입니다."
|
circularReferenceFolder: "지정한 폴더가 이동할 폴더의 하위 폴더입니다."
|
||||||
hasChildFilesOrFolders: "이 폴더는 비어있지 않기 때문에 삭제할 수 없습니다."
|
hasChildFilesOrFolders: "이 폴더는 비어있지 않기 때문에 삭제할 수 없습니다."
|
||||||
|
@ -386,7 +384,7 @@ exploreFediverse: "연합우주를 탐색"
|
||||||
popularTags: "인기 태그"
|
popularTags: "인기 태그"
|
||||||
userList: "리스트"
|
userList: "리스트"
|
||||||
about: "정보"
|
about: "정보"
|
||||||
aboutFirefish: "Misskey에 대하여"
|
aboutFirefish: "Firefish에 대하여"
|
||||||
administrator: "관리자"
|
administrator: "관리자"
|
||||||
token: "토큰"
|
token: "토큰"
|
||||||
twoStepAuthentication: "2단계 인증"
|
twoStepAuthentication: "2단계 인증"
|
||||||
|
@ -537,8 +535,8 @@ sort: "정렬"
|
||||||
ascendingOrder: "오름차순"
|
ascendingOrder: "오름차순"
|
||||||
descendingOrder: "내림차순"
|
descendingOrder: "내림차순"
|
||||||
scratchpad: "스크래치 패드"
|
scratchpad: "스크래치 패드"
|
||||||
scratchpadDescription: "스크래치 패드는 AiScript 의 테스트 환경을 제공합니다. Firefish 와 상호 작용하는 코드를 작성,
|
scratchpadDescription: "스크래치 패드는 AiScript 의 테스트 환경을 제공합니다. Firefish 와 상호 작용하는 코드를
|
||||||
실행 및 결과를 확인할 수 있습니다."
|
작성, 실행 및 결과를 확인할 수 있습니다."
|
||||||
output: "출력"
|
output: "출력"
|
||||||
script: "스크립트"
|
script: "스크립트"
|
||||||
disablePagesScript: "Pages 에서 AiScript 를 사용하지 않음"
|
disablePagesScript: "Pages 에서 AiScript 를 사용하지 않음"
|
||||||
|
@ -572,8 +570,8 @@ disablePlayer: "플레이어 닫기"
|
||||||
expandTweet: "트윗 확장하기"
|
expandTweet: "트윗 확장하기"
|
||||||
themeEditor: "테마 에디터"
|
themeEditor: "테마 에디터"
|
||||||
description: "설명"
|
description: "설명"
|
||||||
describeFile: "캡션 추가"
|
describeFile: "설명 추가"
|
||||||
enterFileDescription: "캡션 입력"
|
enterFileDescription: "설명 입력"
|
||||||
author: "작성자"
|
author: "작성자"
|
||||||
leaveConfirm: "저장하지 않은 변경사항이 있습니다. 취소하시겠습니까?"
|
leaveConfirm: "저장하지 않은 변경사항이 있습니다. 취소하시겠습니까?"
|
||||||
manage: "관리"
|
manage: "관리"
|
||||||
|
@ -703,7 +701,7 @@ experimentalFeatures: "실험실"
|
||||||
developer: "개발자"
|
developer: "개발자"
|
||||||
makeExplorable: "\"발견하기\"에 내 계정 보이기"
|
makeExplorable: "\"발견하기\"에 내 계정 보이기"
|
||||||
makeExplorableDescription: "비활성화하면 \"발견하기\"에 나의 계정을 표시하지 않습니다."
|
makeExplorableDescription: "비활성화하면 \"발견하기\"에 나의 계정을 표시하지 않습니다."
|
||||||
showGapBetweenNotesInTimeline: "타임라인의 노트 사이를 띄워서 표시"
|
showGapBetweenNotesInTimeline: "타임라인의 게시물 사이를 띄워서 표시"
|
||||||
duplicate: "복제"
|
duplicate: "복제"
|
||||||
left: "왼쪽"
|
left: "왼쪽"
|
||||||
center: "가운데"
|
center: "가운데"
|
||||||
|
@ -758,7 +756,7 @@ unlikeConfirm: "좋아요를 취소할까요?"
|
||||||
fullView: "전체 화면"
|
fullView: "전체 화면"
|
||||||
quitFullView: "전체 화면 해제"
|
quitFullView: "전체 화면 해제"
|
||||||
addDescription: "설명 추가"
|
addDescription: "설명 추가"
|
||||||
userPagePinTip: "각 게시물의 메뉴에서 「프로필에 고정」을 선택하는 것으로, 여기에 노트를 표시해 둘 수 있어요."
|
userPagePinTip: "각 게시물의 메뉴에서 「프로필에 고정」을 선택하는 것으로, 여기에 게시물을 표시해 둘 수 있어요."
|
||||||
notSpecifiedMentionWarning: "수신자가 선택되지 않은 멘션이 있어요"
|
notSpecifiedMentionWarning: "수신자가 선택되지 않은 멘션이 있어요"
|
||||||
info: "정보"
|
info: "정보"
|
||||||
userInfo: "유저 정보"
|
userInfo: "유저 정보"
|
||||||
|
@ -789,7 +787,7 @@ gallery: "갤러리"
|
||||||
recentPosts: "최근 포스트"
|
recentPosts: "최근 포스트"
|
||||||
popularPosts: "인기 포스트"
|
popularPosts: "인기 포스트"
|
||||||
shareWithNote: "게시물로 공유"
|
shareWithNote: "게시물로 공유"
|
||||||
ads: "광고"
|
ads: "커뮤니티 배너"
|
||||||
expiration: "기한"
|
expiration: "기한"
|
||||||
memo: "메모"
|
memo: "메모"
|
||||||
priority: "우선순위"
|
priority: "우선순위"
|
||||||
|
@ -811,7 +809,7 @@ hashtags: "해시태그"
|
||||||
troubleshooting: "문제 해결"
|
troubleshooting: "문제 해결"
|
||||||
useBlurEffect: "UI에 흐림 효과 사용"
|
useBlurEffect: "UI에 흐림 효과 사용"
|
||||||
learnMore: "자세히"
|
learnMore: "자세히"
|
||||||
misskeyUpdated: "Misskey가 업데이트 되었습니다!"
|
misskeyUpdated: "Firefish가 업데이트 되었습니다!"
|
||||||
whatIsNew: "패치 정보 보기"
|
whatIsNew: "패치 정보 보기"
|
||||||
translate: "번역"
|
translate: "번역"
|
||||||
translatedFrom: "{x}에서 번역"
|
translatedFrom: "{x}에서 번역"
|
||||||
|
@ -840,7 +838,7 @@ unmuteThread: "글타래 뮤트 해제"
|
||||||
ffVisibility: "내 인맥의 공개 범위"
|
ffVisibility: "내 인맥의 공개 범위"
|
||||||
ffVisibilityDescription: "나의 팔로우와 팔로워 정보에 대한 공개 범위를 설정할 수 있습니다."
|
ffVisibilityDescription: "나의 팔로우와 팔로워 정보에 대한 공개 범위를 설정할 수 있습니다."
|
||||||
continueThread: "이 글타래 이어서 보기"
|
continueThread: "이 글타래 이어서 보기"
|
||||||
deleteAccountConfirm: "계정이 삭제되고 되돌릴 수 없게 됩니다. 계속하시겠습니까? "
|
deleteAccountConfirm: "계정이 삭제되고 되돌릴 수 없게 됩니다. 계속하시겠습니까?"
|
||||||
incorrectPassword: "비밀번호가 올바르지 않습니다."
|
incorrectPassword: "비밀번호가 올바르지 않습니다."
|
||||||
voteConfirm: "\"{choice}\"에 투표하시겠습니까?"
|
voteConfirm: "\"{choice}\"에 투표하시겠습니까?"
|
||||||
hide: "숨기기"
|
hide: "숨기기"
|
||||||
|
@ -992,12 +990,12 @@ _registry:
|
||||||
domain: "도메인"
|
domain: "도메인"
|
||||||
createKey: "키 생성"
|
createKey: "키 생성"
|
||||||
_aboutFirefish:
|
_aboutFirefish:
|
||||||
about: "Misskey는 syuilo에 의해서 2014년부터 개발되어 온 오픈소스 소프트웨어 입니다."
|
about: "Firefish는 ThatOneCalculator에 의해서 2022년부터 개발되어 온 Misskey의 포크 소프트웨어 입니다."
|
||||||
contributors: "주요 기여자"
|
contributors: "주요 기여자"
|
||||||
allContributors: "모든 기여자"
|
allContributors: "모든 기여자"
|
||||||
source: "소스 코드"
|
source: "소스 코드"
|
||||||
translation: "Misskey를 번역하기"
|
translation: "Firefish를 번역하기"
|
||||||
donate: "Misskey에 기부하기"
|
donate: "Firefish에 기부하기"
|
||||||
morePatrons: "이 외에도 다른 많은 분들이 도움을 주시고 계십니다. 감사합니다🥰"
|
morePatrons: "이 외에도 다른 많은 분들이 도움을 주시고 계십니다. 감사합니다🥰"
|
||||||
patrons: "후원자"
|
patrons: "후원자"
|
||||||
patronsList: 기부 금액이 아닌 시간 순서로 정렬합니다. 위 링크를 통해 후원하여 당신의 이름을 새겨 보세요!
|
patronsList: 기부 금액이 아닌 시간 순서로 정렬합니다. 위 링크를 통해 후원하여 당신의 이름을 새겨 보세요!
|
||||||
|
@ -1006,15 +1004,16 @@ _aboutFirefish:
|
||||||
pleaseDonateToFirefish: Firefish의 개발에 후원하는 것을 검토하여 주십시오.
|
pleaseDonateToFirefish: Firefish의 개발에 후원하는 것을 검토하여 주십시오.
|
||||||
donateHost: '{host} 에게 기부하기'
|
donateHost: '{host} 에게 기부하기'
|
||||||
donateTitle: Firefish가 마음에 드시나요?
|
donateTitle: Firefish가 마음에 드시나요?
|
||||||
|
misskeyContributors: 오리지널 Misskey 기여자
|
||||||
_nsfw:
|
_nsfw:
|
||||||
respect: "열람주의로 설정된 미디어 숨기기"
|
respect: "열람주의로 설정된 미디어 숨기기"
|
||||||
ignore: "열람 주의 미디어 항상 표시"
|
ignore: "열람 주의 미디어 항상 표시"
|
||||||
force: "미디어 항상 숨기기"
|
force: "미디어 항상 숨기기"
|
||||||
_mfm:
|
_mfm:
|
||||||
cheatSheet: "MFM 도움말"
|
cheatSheet: "MFM 도움말"
|
||||||
intro: "MFM는 Misskey의 다양한 곳에서 사용할 수 있는 전용 마크업 언어입니다. 여기에서는 MFM에서 사용할 수 있는 구문을 확인할
|
intro: "MFM는 Misskey나 Firefish, Akkoma 외의 다양한 곳에서 사용할 수 있는 전용 마크업 언어입니다. 여기에서는 MFM에서
|
||||||
수 있습니다."
|
사용할 수 있는 구문을 확인할 수 있습니다."
|
||||||
dummy: "Misskey로 연합우주의 세계가 펼쳐집니다"
|
dummy: "Firefish로 연합우주의 세계가 펼쳐집니다"
|
||||||
mention: "멘션"
|
mention: "멘션"
|
||||||
mentionDescription: "골뱅이표(@) 뒤에 사용자명을 넣어 특정 유저를 나타낼 수 있습니다."
|
mentionDescription: "골뱅이표(@) 뒤에 사용자명을 넣어 특정 유저를 나타낼 수 있습니다."
|
||||||
hashtag: "해시태그"
|
hashtag: "해시태그"
|
||||||
|
@ -1134,7 +1133,7 @@ _wordMute:
|
||||||
_instanceMute:
|
_instanceMute:
|
||||||
instanceMuteDescription: "뮤트한 서버에서 오는 답글을 포함한 모든 게시물과 부스트를 뮤트합니다."
|
instanceMuteDescription: "뮤트한 서버에서 오는 답글을 포함한 모든 게시물과 부스트를 뮤트합니다."
|
||||||
instanceMuteDescription2: "한 줄에 하나씩 입력해 주세요"
|
instanceMuteDescription2: "한 줄에 하나씩 입력해 주세요"
|
||||||
title: "지정한 서버의 노트를 숨깁니다."
|
title: "지정한 서버의 게시물을 숨깁니다."
|
||||||
heading: "뮤트할 서버"
|
heading: "뮤트할 서버"
|
||||||
_theme:
|
_theme:
|
||||||
explore: "테마 찾아보기"
|
explore: "테마 찾아보기"
|
||||||
|
@ -1747,7 +1746,7 @@ _notification:
|
||||||
youGotMention: "{name}님이 멘션함"
|
youGotMention: "{name}님이 멘션함"
|
||||||
youGotReply: "{name}님이 답글함"
|
youGotReply: "{name}님이 답글함"
|
||||||
youGotQuote: "{name}님이 인용함"
|
youGotQuote: "{name}님이 인용함"
|
||||||
youRenoted: "{name}님이 Boost"
|
youRenoted: "{name}님의 부스트"
|
||||||
youGotPoll: "{name}님이 투표함"
|
youGotPoll: "{name}님이 투표함"
|
||||||
youGotMessagingMessageFromUser: "{name} 님이 보낸 채팅이 있어요"
|
youGotMessagingMessageFromUser: "{name} 님이 보낸 채팅이 있어요"
|
||||||
youGotMessagingMessageFromGroup: "{name}에서 보낸 채팅이 있어요"
|
youGotMessagingMessageFromGroup: "{name}에서 보낸 채팅이 있어요"
|
||||||
|
@ -1824,7 +1823,7 @@ replayTutorial: 튜토리얼 다시 보기
|
||||||
renoteMute: 부스트 뮤트
|
renoteMute: 부스트 뮤트
|
||||||
antennaInstancesDescription: 서버 호스트를 한 줄에 하나씩 입력하세요
|
antennaInstancesDescription: 서버 호스트를 한 줄에 하나씩 입력하세요
|
||||||
userSaysSomethingReason: '{name} 님이 {reason}에 대해 말했습니다'
|
userSaysSomethingReason: '{name} 님이 {reason}에 대해 말했습니다'
|
||||||
userSaysSomethingReasonQuote: '{name} 님이 {reason} 을 포함하는 노트를 인용했습니다'
|
userSaysSomethingReasonQuote: '{name} 님이 {reason} 을 포함하는 게시물을 인용했습니다'
|
||||||
pushNotification: 푸시 알림
|
pushNotification: 푸시 알림
|
||||||
channelFederationWarn: 현재 채널은 다른 서버로 연합되지 않습니다
|
channelFederationWarn: 현재 채널은 다른 서버로 연합되지 않습니다
|
||||||
enableServerMachineStats: 서버의 머신 정보를 공개
|
enableServerMachineStats: 서버의 머신 정보를 공개
|
||||||
|
@ -1836,7 +1835,7 @@ cannotUploadBecauseExceedsFileSizeLimit: 파일 크기 제한을 초과하여
|
||||||
pushNotificationNotSupported: 브라우저 및 서버가 푸시 알림을 지원하지 않습니다
|
pushNotificationNotSupported: 브라우저 및 서버가 푸시 알림을 지원하지 않습니다
|
||||||
enableRecommendedTimeline: 추천 타임라인을 활성화
|
enableRecommendedTimeline: 추천 타임라인을 활성화
|
||||||
pushNotificationAlreadySubscribed: 푸시 알림이 활성화되었습니다
|
pushNotificationAlreadySubscribed: 푸시 알림이 활성화되었습니다
|
||||||
caption: 자동 캡션
|
caption: 자동으로 설명 붙이기
|
||||||
findOtherInstance: 다른 서버 둘러보기
|
findOtherInstance: 다른 서버 둘러보기
|
||||||
enableIdenticonGeneration: 유저 별 Identicon의 생성을 활성화
|
enableIdenticonGeneration: 유저 별 Identicon의 생성을 활성화
|
||||||
secureModeInfo: 인증 정보가 없는 리모트 서버로부터의 요청에 응답하지 않습니다.
|
secureModeInfo: 인증 정보가 없는 리모트 서버로부터의 요청에 응답하지 않습니다.
|
||||||
|
@ -1858,7 +1857,7 @@ customKaTeXMacroDescription: 'KaTeX 매크로를 지정하여 수식을 더욱
|
||||||
사용할 수 없습니다. 올바르지 않은 정의는 무시됩니다. 문자열을 치환하는 수준에서만 지원하며, 조건 분기와 같은 고도의 구문은 사용할 수 없습니다.'
|
사용할 수 없습니다. 올바르지 않은 정의는 무시됩니다. 문자열을 치환하는 수준에서만 지원하며, 조건 분기와 같은 고도의 구문은 사용할 수 없습니다.'
|
||||||
reactionPickerSkinTone: 선호하는 이모지 피부 톤
|
reactionPickerSkinTone: 선호하는 이모지 피부 톤
|
||||||
selectInstance: 서버 선택
|
selectInstance: 서버 선택
|
||||||
showAds: 광고 보이기
|
showAds: 커뮤니티 배너를 보이기
|
||||||
searchPlaceholder: Firefish에서 검색
|
searchPlaceholder: Firefish에서 검색
|
||||||
addInstance: 서버 추가
|
addInstance: 서버 추가
|
||||||
listsDesc: 리스트를 사용하여 특정 유저로 이루어진 타임라인을 구성할 수 있습니다. 리스트는 '타임라인' 페이지에서 접근할 수 있습니다.
|
listsDesc: 리스트를 사용하여 특정 유저로 이루어진 타임라인을 구성할 수 있습니다. 리스트는 '타임라인' 페이지에서 접근할 수 있습니다.
|
||||||
|
@ -1867,7 +1866,7 @@ showEmojisInReactionNotifications: 리액션 알림에 이모지 보이기
|
||||||
hiddenTagsDescription: 트렌드와 '발견하기'에서 제외할 해시태그를 ('#'을 제외하고) 한 줄에 하나씩 입력하여 주십시오. 이 설정은
|
hiddenTagsDescription: 트렌드와 '발견하기'에서 제외할 해시태그를 ('#'을 제외하고) 한 줄에 하나씩 입력하여 주십시오. 이 설정은
|
||||||
트렌드와 '발견하기' 외에는 영향을 주지 않습니다.
|
트렌드와 '발견하기' 외에는 영향을 주지 않습니다.
|
||||||
antennasDesc: "안테나에서는 조건에 맞는 게시물이 표시됩니다.\n'타임라인' 페이지에서 접근할 수 있습니다."
|
antennasDesc: "안테나에서는 조건에 맞는 게시물이 표시됩니다.\n'타임라인' 페이지에서 접근할 수 있습니다."
|
||||||
expandOnNoteClick: 노트를 클릭하여 자세히 표시
|
expandOnNoteClick: 게시물을 클릭하여 자세히 표시
|
||||||
expandOnNoteClickDesc: 비활성화한 경우에도 우클릭 메뉴 또는 타임스탬프를 클릭하여 열 수 있습니다.
|
expandOnNoteClickDesc: 비활성화한 경우에도 우클릭 메뉴 또는 타임스탬프를 클릭하여 열 수 있습니다.
|
||||||
customMOTDDescription: 유저가 페이지를 로딩/새로고침할 때 마다 무작위로 표시할 메시지를 한 줄에 하나씩 입력합니다.
|
customMOTDDescription: 유저가 페이지를 로딩/새로고침할 때 마다 무작위로 표시할 메시지를 한 줄에 하나씩 입력합니다.
|
||||||
moveFrom: 다른 계정에서 이 계정으로 이사하기
|
moveFrom: 다른 계정에서 이 계정으로 이사하기
|
||||||
|
@ -1887,7 +1886,7 @@ swipeOnDesktop: 데스크톱에서도 모바일과 같은 스와이프를 사용
|
||||||
migration: 계정 이사
|
migration: 계정 이사
|
||||||
moveTo: 이 계정에서 새로운 계정으로 이사
|
moveTo: 이 계정에서 새로운 계정으로 이사
|
||||||
deleted: 삭제됨
|
deleted: 삭제됨
|
||||||
editNote: 노트 편집
|
editNote: 게시물 편집
|
||||||
edited: '편짐됨: {date} {time}'
|
edited: '편짐됨: {date} {time}'
|
||||||
customMOTD: 사용자 지정 MOTD (스플래시 화면 메시지)
|
customMOTD: 사용자 지정 MOTD (스플래시 화면 메시지)
|
||||||
selectChannel: 채널 선택
|
selectChannel: 채널 선택
|
||||||
|
@ -1896,14 +1895,14 @@ splash: 스플래시 화면
|
||||||
preventAiLearningDescription: 업로드한 게시물이나 미디어를 AI 모델이 학습하지 말기를 요구합니다.
|
preventAiLearningDescription: 업로드한 게시물이나 미디어를 AI 모델이 학습하지 말기를 요구합니다.
|
||||||
isBot: 이 계정은 봇입니다
|
isBot: 이 계정은 봇입니다
|
||||||
isAdmin: 관리자
|
isAdmin: 관리자
|
||||||
newer: 새로운 노트
|
newer: 새로운 게시물
|
||||||
older: 이전 노트
|
older: 이전 게시물
|
||||||
renoteUnmute: 부스트 뮤트 해제
|
renoteUnmute: 부스트 뮤트 해제
|
||||||
accountMoved: '이 유저는 다른 계정으로 이사했습니다:'
|
accountMoved: '이 유저는 다른 계정으로 이사했습니다:'
|
||||||
silencedInstances: 사일런스한 서버
|
silencedInstances: 사일런스한 서버
|
||||||
accessibility: 접근성
|
accessibility: 접근성
|
||||||
userSaysSomethingReasonReply: '{name} 님이 {reason} 을 포함하는 노트에 답글했습니다'
|
userSaysSomethingReasonReply: '{name} 님이 {reason} 을 포함하는 게시물에 답글했습니다'
|
||||||
userSaysSomethingReasonRenote: '{name} 님이 {reason} 을 포함하는 노트를 부스트했습니다'
|
userSaysSomethingReasonRenote: '{name} 님이 {reason} 을 포함하는 게시물을 부스트했습니다'
|
||||||
breakFollowConfirm: 팔로워를 해제하시겠습니까?
|
breakFollowConfirm: 팔로워를 해제하시겠습니까?
|
||||||
indexFrom: 이 게시물 ID부터 인덱싱하기
|
indexFrom: 이 게시물 ID부터 인덱싱하기
|
||||||
noThankYou: 괜찮습니다
|
noThankYou: 괜찮습니다
|
||||||
|
@ -1949,8 +1948,8 @@ silencedWarning: 관리자가 사일런스한 서버에 속한 유저이며, 스
|
||||||
isModerator: 모더레이터
|
isModerator: 모더레이터
|
||||||
isPatron: Firefish 후원자
|
isPatron: Firefish 후원자
|
||||||
_experiments:
|
_experiments:
|
||||||
postImportsCaption: 유저가 과거에 작성한 게시물을 Firefish(Firefish), Misskey, Mastodon, Akkoma,
|
postImportsCaption: 유저가 과거에 작성한 게시물을 Firefish, Misskey, Mastodon, Akkoma, Pleroma
|
||||||
Pleroma 등에서 가져올 수 있게 합니다. 작업 대기열의 처리 속도가 느릴 경우 서비스에 영향이 갈 수 있습니다.
|
등에서 가져올 수 있게 합니다. 작업 대기열의 처리 속도가 느릴 경우 서비스에 영향이 갈 수 있습니다.
|
||||||
enablePostImports: 게시물 가져오기를 활성화
|
enablePostImports: 게시물 가져오기를 활성화
|
||||||
title: 실험실
|
title: 실험실
|
||||||
_messaging:
|
_messaging:
|
||||||
|
@ -1958,8 +1957,8 @@ _messaging:
|
||||||
dms: 개인 메시지
|
dms: 개인 메시지
|
||||||
_tutorial:
|
_tutorial:
|
||||||
title: Firefly의 사용 방법
|
title: Firefly의 사용 방법
|
||||||
step5_5: '{icon} 소셜 타임라인은 홈 타임라인과 소셜 타임라인을 합친 것과 같습니다.'
|
step5_5: '{icon} 소셜 타임라인은 홈 타임라인과 로컬 타임라인을 합친 것과 같습니다.'
|
||||||
step4_1: 첫 노트를 올려 봅시다.
|
step4_1: 첫 글을 올려 봅시다.
|
||||||
step5_3: '{icon} 홈 타임라인은 내가 팔로우하고 있는 계정의 게시물을 볼 수 있는 타임라인입니다.'
|
step5_3: '{icon} 홈 타임라인은 내가 팔로우하고 있는 계정의 게시물을 볼 수 있는 타임라인입니다.'
|
||||||
step6_2: 이 서버에 가입을 마친 당신은 단순히 Firefish 서버의 유저가 아닌, 수많은 서버가 서로 상호작용하는 연합우주에 참가하시게
|
step6_2: 이 서버에 가입을 마친 당신은 단순히 Firefish 서버의 유저가 아닌, 수많은 서버가 서로 상호작용하는 연합우주에 참가하시게
|
||||||
된 것입니다.
|
된 것입니다.
|
||||||
|
@ -2003,3 +2002,17 @@ _feeds:
|
||||||
_dialog:
|
_dialog:
|
||||||
charactersExceeded: 글자 수 제한을 초과했습니다! 현재 {current}자 / 최대 {max}자
|
charactersExceeded: 글자 수 제한을 초과했습니다! 현재 {current}자 / 최대 {max}자
|
||||||
charactersBelow: 최소 글자 수 보다 작습니다! 현재 {current}자 / 최소 {max}자
|
charactersBelow: 최소 글자 수 보다 작습니다! 현재 {current}자 / 최소 {max}자
|
||||||
|
emojiPackCreator: 이모지 팩 만든이
|
||||||
|
objectStorageS3ForcePathStyleDesc: Endpoint URL을 '<bucket>.s3.amazonaws.com'가 아닌 's3.amazonaws.com/<bucket>/'와
|
||||||
|
같은 형식으로 사용할 경우에 활성화해 주세요.
|
||||||
|
confirm: 확인
|
||||||
|
importZip: ZIP으로 가져오기
|
||||||
|
exportZip: ZIP으로 내보내기
|
||||||
|
origin: 원본
|
||||||
|
objectStorageS3ForcePathStyle: 경로 기반 Endpoint URL을 사용하기
|
||||||
|
delete2fa: 2FA를 비활성화
|
||||||
|
delete2faConfirm: 이 계정에서 2FA를 영구히 삭제합니다. 계속하시겠습니까?
|
||||||
|
deletePasskeys: 보안 키 삭제
|
||||||
|
deletePasskeysConfirm: 이 계정에서 모든 보안 키를 영구히 삭제합니다. 계속하시겠습니까?
|
||||||
|
inputNotMatch: 입력이 일치하지 않습니다
|
||||||
|
addRe: 열람주의로 표시된 게시물의 답장에 're:' 붙이기
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
|
||||||
_lang_: "Português"
|
_lang_: "Português"
|
||||||
headlineFirefish: "Uma rede ligada por notas"
|
headlineFirefish: "Uma rede ligada por notas"
|
||||||
introFirefish: "Bem-vindo! Firefish é um serviço de microblogue descentralizado de código aberto.\nCria \"notas\" e partilha o que te ocorre com todos à tua volta. 📡\nCom \"reações\" podes também expressar logo o que sentes às notas de todos. 👍\nExploremos um novo mundo! 🚀"
|
introFirefish: "Bem-vindo! Firefish é um serviço de microblogue descentralizado de
|
||||||
|
código aberto, gratuito para sempre! 🚀"
|
||||||
monthAndDay: "{day}/{month}"
|
monthAndDay: "{day}/{month}"
|
||||||
search: "Buscar"
|
search: "Buscar"
|
||||||
notifications: "Notificações"
|
notifications: "Notificações"
|
||||||
|
@ -44,7 +44,8 @@ copyContent: "Copiar conteúdos"
|
||||||
copyLink: "Copiar hiperligação"
|
copyLink: "Copiar hiperligação"
|
||||||
delete: "Eliminar"
|
delete: "Eliminar"
|
||||||
deleteAndEdit: "Eliminar e editar"
|
deleteAndEdit: "Eliminar e editar"
|
||||||
deleteAndEditConfirm: "Tens a certeza que pretendes eliminar esta nota e editá-la? Irás perder todas as suas reações, renotas e respostas."
|
deleteAndEditConfirm: "Tens a certeza que pretendes eliminar esta nota e editá-la?
|
||||||
|
Irás perder todas as suas reações, renotas e respostas."
|
||||||
addToList: "Adicionar a lista"
|
addToList: "Adicionar a lista"
|
||||||
sendMessage: "Enviar uma mensagem"
|
sendMessage: "Enviar uma mensagem"
|
||||||
copyUsername: "Copiar nome de utilizador"
|
copyUsername: "Copiar nome de utilizador"
|
||||||
|
@ -64,9 +65,11 @@ import: "Importar"
|
||||||
export: "Exportar"
|
export: "Exportar"
|
||||||
files: "Ficheiros"
|
files: "Ficheiros"
|
||||||
download: "Descarregar"
|
download: "Descarregar"
|
||||||
driveFileDeleteConfirm: "Tens a certeza que pretendes apagar o ficheiro \"{name}\"? As notas que tenham este ficheiro anexado serão também apagadas."
|
driveFileDeleteConfirm: "Tens a certeza que pretendes apagar o ficheiro \"{name}\"\
|
||||||
|
? As notas que tenham este ficheiro anexado serão também apagadas."
|
||||||
unfollowConfirm: "Tens a certeza que queres deixar de seguir {name}?"
|
unfollowConfirm: "Tens a certeza que queres deixar de seguir {name}?"
|
||||||
exportRequested: "Pediste uma exportação. Este processo pode demorar algum tempo. Será adicionado à tua Drive após a conclusão do processo."
|
exportRequested: "Pediste uma exportação. Este processo pode demorar algum tempo.
|
||||||
|
Será adicionado à tua Drive após a conclusão do processo."
|
||||||
importRequested: "Pediste uma importação. Este processo pode demorar algum tempo."
|
importRequested: "Pediste uma importação. Este processo pode demorar algum tempo."
|
||||||
lists: "Listas"
|
lists: "Listas"
|
||||||
noLists: "Não tens nenhuma lista"
|
noLists: "Não tens nenhuma lista"
|
||||||
|
@ -81,9 +84,12 @@ error: "Erro"
|
||||||
somethingHappened: "Ocorreu um erro"
|
somethingHappened: "Ocorreu um erro"
|
||||||
retry: "Tentar novamente"
|
retry: "Tentar novamente"
|
||||||
pageLoadError: "Ocorreu um erro ao carregar a página."
|
pageLoadError: "Ocorreu um erro ao carregar a página."
|
||||||
pageLoadErrorDescription: "Isto é normalmente causado por erros de rede ou pela cache do browser. Experimenta limpar a cache e tenta novamente após algum tempo."
|
pageLoadErrorDescription: "Isto é normalmente causado por erros de rede ou pela cache
|
||||||
serverIsDead: "O servidor não está respondendo. Por favor espere um pouco e tente novamente."
|
do browser. Experimenta limpar a cache e tenta novamente após algum tempo."
|
||||||
youShouldUpgradeClient: "Para visualizar essa página, por favor recarregue-a para atualizar seu cliente."
|
serverIsDead: "O servidor não está respondendo. Por favor espere um pouco e tente
|
||||||
|
novamente."
|
||||||
|
youShouldUpgradeClient: "Para visualizar essa página, por favor recarregue-a para
|
||||||
|
atualizar seu cliente."
|
||||||
enterListName: "Insira um nome para a lista"
|
enterListName: "Insira um nome para a lista"
|
||||||
privacy: "Privacidade"
|
privacy: "Privacidade"
|
||||||
makeFollowManuallyApprove: "Pedidos de seguimento precisam ser aprovados"
|
makeFollowManuallyApprove: "Pedidos de seguimento precisam ser aprovados"
|
||||||
|
@ -108,7 +114,8 @@ sensitive: "Conteúdo sensível"
|
||||||
add: "Adicionar"
|
add: "Adicionar"
|
||||||
reaction: "Reações"
|
reaction: "Reações"
|
||||||
reactionSetting: "Quais reações a mostrar no selecionador de reações"
|
reactionSetting: "Quais reações a mostrar no selecionador de reações"
|
||||||
reactionSettingDescription2: "Arraste para reordenar, clique para excluir, pressione + para adicionar."
|
reactionSettingDescription2: "Arraste para reordenar, clique para excluir, pressione
|
||||||
|
+ para adicionar."
|
||||||
rememberNoteVisibility: "Lembrar das configurações de visibilidade de notas"
|
rememberNoteVisibility: "Lembrar das configurações de visibilidade de notas"
|
||||||
attachCancel: "Remover anexo"
|
attachCancel: "Remover anexo"
|
||||||
markAsSensitive: "Marcar como sensível"
|
markAsSensitive: "Marcar como sensível"
|
||||||
|
@ -137,13 +144,18 @@ emojiUrl: "URL do Emoji"
|
||||||
addEmoji: "Adicionar um Emoji"
|
addEmoji: "Adicionar um Emoji"
|
||||||
settingGuide: "Guia de configuração"
|
settingGuide: "Guia de configuração"
|
||||||
cacheRemoteFiles: "Memória transitória de arquivos remotos"
|
cacheRemoteFiles: "Memória transitória de arquivos remotos"
|
||||||
cacheRemoteFilesDescription: "Se você desabilitar essa configuração, os arquivos remotos não serão armazenados em memória transitória e serão vinculados diretamente. Economiza o armazenamento do servidor, mas não gera miniaturas, o que aumenta o tráfego."
|
cacheRemoteFilesDescription: "Se você desabilitar essa configuração, os arquivos remotos
|
||||||
|
não serão armazenados em memória transitória e serão vinculados diretamente. Economiza
|
||||||
|
o armazenamento do servidor, mas não gera miniaturas, o que aumenta o tráfego."
|
||||||
flagAsBot: "Marcar conta como robô"
|
flagAsBot: "Marcar conta como robô"
|
||||||
flagAsBotDescription: "Se esta conta for operada por um programa, ative este sinalizador. Quando ativado, serve como um sinalizador para evitar o encadeamento de reações para outros programadores, e o manuseio do sistema do Firefish é adequado para ‘bots’."
|
flagAsBotDescription: "Se esta conta for operada por um programa, ative este sinalizador.
|
||||||
|
Quando ativado, serve como um sinalizador para evitar o encadeamento de reações
|
||||||
|
para outros programadores, e o manuseio do sistema do Firefish é adequado para ‘bots’."
|
||||||
flagAsCat: "Marcar conta como gato"
|
flagAsCat: "Marcar conta como gato"
|
||||||
flagAsCatDescription: "Ative essa opção para marcar essa conta como gato."
|
flagAsCatDescription: "Ative essa opção para marcar essa conta como gato."
|
||||||
flagShowTimelineReplies: "Mostrar respostas na linha de tempo"
|
flagShowTimelineReplies: "Mostrar respostas na linha de tempo"
|
||||||
flagShowTimelineRepliesDescription: "Quando ativado, a linha do tempo mostra as respostas às outras notas do utilizador, além da nota do utilizador."
|
flagShowTimelineRepliesDescription: "Quando ativado, a linha do tempo mostra as respostas
|
||||||
|
às outras notas do utilizador, além da nota do utilizador."
|
||||||
autoAcceptFollowed: "Aprove automaticamente os seguidores dos seguintes utilizadores"
|
autoAcceptFollowed: "Aprove automaticamente os seguidores dos seguintes utilizadores"
|
||||||
addAccount: "Adicionar Conta"
|
addAccount: "Adicionar Conta"
|
||||||
loginFailed: "Não consegui logar"
|
loginFailed: "Não consegui logar"
|
||||||
|
@ -156,7 +168,10 @@ searchWith: "Buscar: {q}"
|
||||||
youHaveNoLists: "Não tem nenhuma lista"
|
youHaveNoLists: "Não tem nenhuma lista"
|
||||||
followConfirm: "Tem certeza que quer deixar de seguir {name}?"
|
followConfirm: "Tem certeza que quer deixar de seguir {name}?"
|
||||||
proxyAccount: "Conta proxy"
|
proxyAccount: "Conta proxy"
|
||||||
proxyAccountDescription: "Uma conta proxy é uma conta que atua como seguidora remota para utilizadores sob determinadas condições. Por exemplo, quando um utilizador lista um utilizador remoto, a atividade não será entregue à instância, a menos que alguém esteja seguindo o utilizador listado, portanto, a conta proxy deve seguir."
|
proxyAccountDescription: "Uma conta proxy é uma conta que atua como seguidora remota
|
||||||
|
para utilizadores sob determinadas condições. Por exemplo, quando um utilizador
|
||||||
|
lista um utilizador remoto, a atividade não será entregue à instância, a menos que
|
||||||
|
alguém esteja seguindo o utilizador listado, portanto, a conta proxy deve seguir."
|
||||||
host: "hospedeiro"
|
host: "hospedeiro"
|
||||||
selectUser: "Selecionar utilizador"
|
selectUser: "Selecionar utilizador"
|
||||||
recipient: "Morada"
|
recipient: "Morada"
|
||||||
|
@ -186,11 +201,15 @@ instanceInfo: "Informações da instância"
|
||||||
statistics: "Estatisticas"
|
statistics: "Estatisticas"
|
||||||
clearQueue: "Limpar a fila"
|
clearQueue: "Limpar a fila"
|
||||||
clearQueueConfirmTitle: "Quer limpar a fila?"
|
clearQueueConfirmTitle: "Quer limpar a fila?"
|
||||||
clearQueueConfirmText: "Postagens não entregues não serão mais entregues. Normalmente você não precisa fazer isso."
|
clearQueueConfirmText: "Postagens não entregues não serão mais entregues. Normalmente
|
||||||
|
você não precisa fazer isso."
|
||||||
clearCachedFiles: "Limpar memória transitória"
|
clearCachedFiles: "Limpar memória transitória"
|
||||||
clearCachedFilesConfirm: "Tem certeza de que deseja excluir todos os arquivos remotos armazenados em memória transitória?"
|
clearCachedFilesConfirm: "Tem certeza de que deseja excluir todos os arquivos remotos
|
||||||
|
armazenados em memória transitória?"
|
||||||
blockedInstances: "Instância bloqueada"
|
blockedInstances: "Instância bloqueada"
|
||||||
blockedInstancesDescription: "Defina os anfitriões das instâncias que deseja bloquear, separados por quebras de linha. Uma instância bloqueada não poderá interagir com esta instância."
|
blockedInstancesDescription: "Defina os anfitriões das instâncias que deseja bloquear,
|
||||||
|
separados por quebras de linha. Uma instância bloqueada não poderá interagir com
|
||||||
|
esta instância."
|
||||||
muteAndBlock: "Silenciar e bloquear"
|
muteAndBlock: "Silenciar e bloquear"
|
||||||
mutedUsers: "Silenciar utilizador"
|
mutedUsers: "Silenciar utilizador"
|
||||||
blockedUsers: "Utilizadores bloqueados"
|
blockedUsers: "Utilizadores bloqueados"
|
||||||
|
@ -238,7 +257,9 @@ saved: "Salvo"
|
||||||
messaging: "Chat"
|
messaging: "Chat"
|
||||||
upload: "Enviando"
|
upload: "Enviando"
|
||||||
keepOriginalUploading: "Manter a imagem original"
|
keepOriginalUploading: "Manter a imagem original"
|
||||||
keepOriginalUploadingDescription: "Mantenha a versão original ao carregar a imagem. Quando desligado, a imagem para publicação na web será gerada no navegador no momento do upload."
|
keepOriginalUploadingDescription: "Mantenha a versão original ao carregar a imagem.
|
||||||
|
Quando desligado, a imagem para publicação na web será gerada no navegador no momento
|
||||||
|
do upload."
|
||||||
fromDrive: "\nDa unidade"
|
fromDrive: "\nDa unidade"
|
||||||
fromUrl: "Da URL"
|
fromUrl: "Da URL"
|
||||||
uploadFromUrl: "Carregamento de URL"
|
uploadFromUrl: "Carregamento de URL"
|
||||||
|
@ -262,8 +283,8 @@ yearsOld: "{age} anos"
|
||||||
registeredDate: "Data de registro"
|
registeredDate: "Data de registro"
|
||||||
location: "Lugar, colocar"
|
location: "Lugar, colocar"
|
||||||
theme: "tema"
|
theme: "tema"
|
||||||
themeForLightMode: "Temas usados no modo de luz"
|
themeForLightMode: "Tema a usar no Modo Diurno"
|
||||||
themeForDarkMode: "Temas usados no modo escuro"
|
themeForDarkMode: "Temas usados no Modo Noturno"
|
||||||
light: "Claro"
|
light: "Claro"
|
||||||
dark: "Escuro"
|
dark: "Escuro"
|
||||||
lightThemes: "Tema claro"
|
lightThemes: "Tema claro"
|
||||||
|
@ -271,7 +292,7 @@ darkThemes: "Tema escuro"
|
||||||
syncDeviceDarkMode: "Sincronize com o modo escuro do dispositivo"
|
syncDeviceDarkMode: "Sincronize com o modo escuro do dispositivo"
|
||||||
drive: "Unidades"
|
drive: "Unidades"
|
||||||
fileName: "Nome do Ficheiro"
|
fileName: "Nome do Ficheiro"
|
||||||
selectFile: "Selecione os arquivos"
|
selectFile: "Selecione o arquivo"
|
||||||
selectFiles: "Selecione os arquivos"
|
selectFiles: "Selecione os arquivos"
|
||||||
selectFolder: "Selecionar uma pasta"
|
selectFolder: "Selecionar uma pasta"
|
||||||
selectFolders: "Selecionar uma pasta"
|
selectFolders: "Selecionar uma pasta"
|
||||||
|
@ -286,8 +307,9 @@ emptyFolder: "A pasta está vazia"
|
||||||
unableToDelete: "Não é possível eliminar"
|
unableToDelete: "Não é possível eliminar"
|
||||||
inputNewFileName: "Por favor, digite um novo nome para a pasta!"
|
inputNewFileName: "Por favor, digite um novo nome para a pasta!"
|
||||||
inputNewDescription: "Insira uma nova legenda"
|
inputNewDescription: "Insira uma nova legenda"
|
||||||
inputNewFolderName: "Por favor, digite um novo nome para a pasta!"
|
inputNewFolderName: "Por favor, digite um novo nome para a pasta"
|
||||||
circularReferenceFolder: "A pasta de destino é uma subpasta da pasta que você deseja mover."
|
circularReferenceFolder: "A pasta de destino é uma subpasta da pasta que você deseja
|
||||||
|
mover."
|
||||||
hasChildFilesOrFolders: "Esta pasta não está vazia e não pode ser excluída."
|
hasChildFilesOrFolders: "Esta pasta não está vazia e não pode ser excluída."
|
||||||
copyUrl: "Copiar URL"
|
copyUrl: "Copiar URL"
|
||||||
rename: "Renomear"
|
rename: "Renomear"
|
||||||
|
@ -321,7 +343,8 @@ connectService: "Conectar"
|
||||||
disconnectService: "Desconectar"
|
disconnectService: "Desconectar"
|
||||||
enableLocalTimeline: "Ativar linha do tempo local"
|
enableLocalTimeline: "Ativar linha do tempo local"
|
||||||
enableGlobalTimeline: "Ativar linha do tempo global"
|
enableGlobalTimeline: "Ativar linha do tempo global"
|
||||||
disablingTimelinesInfo: "Se você desabilitar essas linhas do tempo, administradores e moderadores ainda poderão usá-las por conveniência."
|
disablingTimelinesInfo: "Se você desabilitar essas linhas do tempo, administradores
|
||||||
|
e moderadores ainda poderão usá-las por conveniência."
|
||||||
registration: "Registar"
|
registration: "Registar"
|
||||||
enableRegistration: "Permitir que qualquer pessoa se registre"
|
enableRegistration: "Permitir que qualquer pessoa se registre"
|
||||||
invite: "Convidar"
|
invite: "Convidar"
|
||||||
|
@ -333,9 +356,11 @@ bannerUrl: "URL da imagem do ‘banner’"
|
||||||
backgroundImageUrl: "URL da imagem de fundo"
|
backgroundImageUrl: "URL da imagem de fundo"
|
||||||
basicInfo: "Informações básicas"
|
basicInfo: "Informações básicas"
|
||||||
pinnedUsers: "Utilizador fixado"
|
pinnedUsers: "Utilizador fixado"
|
||||||
pinnedUsersDescription: "Descreva os utilizadores que você deseja fixar na página \"Localizar\", etc., separados por quebras de linha."
|
pinnedUsersDescription: "Descreva os utilizadores que você deseja fixar na página
|
||||||
|
\"Localizar\", etc., separados por quebras de linha."
|
||||||
pinnedPages: "Página fixada"
|
pinnedPages: "Página fixada"
|
||||||
pinnedPagesDescription: "Descreva o caminho da página que você deseja fixar na página superior da instância, separada por quebras de linha."
|
pinnedPagesDescription: "Descreva o caminho da página que você deseja fixar na página
|
||||||
|
superior da instância, separada por quebras de linha."
|
||||||
pinnedClipId: "ID do clipe a ser fixado"
|
pinnedClipId: "ID do clipe a ser fixado"
|
||||||
pinnedNotes: "Post fixado"
|
pinnedNotes: "Post fixado"
|
||||||
hcaptcha: "hCaptcha"
|
hcaptcha: "hCaptcha"
|
||||||
|
@ -346,18 +371,21 @@ recaptcha: "reCAPTCHA"
|
||||||
enableRecaptcha: "Habilitar reCAPTCHA"
|
enableRecaptcha: "Habilitar reCAPTCHA"
|
||||||
recaptchaSiteKey: "Chave do sítio ‘web’"
|
recaptchaSiteKey: "Chave do sítio ‘web’"
|
||||||
recaptchaSecretKey: "Chave secreta"
|
recaptchaSecretKey: "Chave secreta"
|
||||||
avoidMultiCaptchaConfirm: "O uso de vários captchas pode causar interferência. Deseja desativar outros captchas? Você também pode cancelar e deixar vários captchas ativados."
|
avoidMultiCaptchaConfirm: "O uso de vários captchas pode causar interferência. Deseja
|
||||||
|
desativar outros captchas? Você também pode cancelar e deixar vários captchas ativados."
|
||||||
antennas: "Antenas"
|
antennas: "Antenas"
|
||||||
manageAntennas: "Gestão de antena"
|
manageAntennas: "Gestão de antena"
|
||||||
name: "Nome"
|
name: "Nome"
|
||||||
antennaSource: "Origem de entrada"
|
antennaSource: "Origem de entrada"
|
||||||
antennaKeywords: "Palavras-chave recebidas"
|
antennaKeywords: "Palavras-chave recebidas"
|
||||||
antennaExcludeKeywords: "Palavras-chave negativas"
|
antennaExcludeKeywords: "Palavras-chave negativas"
|
||||||
antennaKeywordsDescription: "Se você separá-lo com um espaço, será uma especificação AND, e se você separá-lo com uma quebra de linha, será uma especificação OR."
|
antennaKeywordsDescription: "Se você separá-lo com um espaço, será uma especificação
|
||||||
|
AND, e se você separá-lo com uma quebra de linha, será uma especificação OR."
|
||||||
notifyAntenna: "Notificar novas notas"
|
notifyAntenna: "Notificar novas notas"
|
||||||
withFileAntenna: "Apenas notas com arquivos anexados"
|
withFileAntenna: "Apenas notas com arquivos anexados"
|
||||||
enableServiceworker: "Ative as notificações push para o seu navegador"
|
enableServiceworker: "Ative as notificações push para o seu navegador"
|
||||||
antennaUsersDescription: "Especificar nomes de utilizador separados por quebras de linha"
|
antennaUsersDescription: "Especificar nomes de utilizador separados por quebras de
|
||||||
|
linha"
|
||||||
caseSensitive: "Maiúsculas e minúsculas"
|
caseSensitive: "Maiúsculas e minúsculas"
|
||||||
withReplies: "Incluindo resposta"
|
withReplies: "Incluindo resposta"
|
||||||
connectedTo: "Você está conectado à seguinte conta"
|
connectedTo: "Você está conectado à seguinte conta"
|
||||||
|
@ -433,15 +461,19 @@ showFeaturedNotesInTimeline: "Mostrar notas recomendadas na linha do tempo"
|
||||||
objectStorage: "Armazenamento de objetos"
|
objectStorage: "Armazenamento de objetos"
|
||||||
useObjectStorage: "Usar armazenamento de objetos"
|
useObjectStorage: "Usar armazenamento de objetos"
|
||||||
objectStorageBaseUrl: "URL base"
|
objectStorageBaseUrl: "URL base"
|
||||||
objectStorageBaseUrlDesc: "O URL usado para referência. Se você estiver usando um CDN ou Proxy, seu URL, S3:'https: // <bucket> .s3.amazonaws.com', GCS, etc .:'https://storage.googleapis.com/ <bucket>' ."
|
objectStorageBaseUrlDesc: "O URL usado para referência. Se você estiver usando um
|
||||||
|
CDN ou Proxy, seu URL, S3:'https: // <bucket> .s3.amazonaws.com', GCS, etc .:'https://storage.googleapis.com/
|
||||||
|
<bucket>' ."
|
||||||
objectStorageBucket: "Bucket"
|
objectStorageBucket: "Bucket"
|
||||||
objectStorageBucketDesc: "Especifique o nome do bucket do serviço a ser usado."
|
objectStorageBucketDesc: "Especifique o nome do bucket do serviço a ser usado."
|
||||||
objectStoragePrefix: "Prefixo"
|
objectStoragePrefix: "Prefixo"
|
||||||
objectStoragePrefixDesc: "Ele é armazenado neste diretório de prefixo."
|
objectStoragePrefixDesc: "Ele é armazenado neste diretório de prefixo."
|
||||||
objectStorageEndpoint: "Ponto final"
|
objectStorageEndpoint: "Ponto final"
|
||||||
objectStorageEndpointDesc: "Especifique vazio para S3, caso contrário, especifique o ponto final para cada serviço. Especifique como'<host>'ou'<host>: <port>'."
|
objectStorageEndpointDesc: "Especifique vazio para S3, caso contrário, especifique
|
||||||
|
o ponto final para cada serviço. Especifique como'<host>'ou'<host>: <port>'."
|
||||||
objectStorageRegion: "Região"
|
objectStorageRegion: "Região"
|
||||||
objectStorageRegionDesc: "Especifique uma região como 'xx-east-1'. Caso seu serviço não tenha o conceito de região, ele deve estar vazio ou 'us-east-1'."
|
objectStorageRegionDesc: "Especifique uma região como 'xx-east-1'. Caso seu serviço
|
||||||
|
não tenha o conceito de região, ele deve estar vazio ou 'us-east-1'."
|
||||||
objectStorageUseSSL: "Usar SSL"
|
objectStorageUseSSL: "Usar SSL"
|
||||||
objectStorageUseSSLDesc: "Desative-o se não quiser usar https para conexões de API"
|
objectStorageUseSSLDesc: "Desative-o se não quiser usar https para conexões de API"
|
||||||
objectStorageUseProxy: "Usar proxy"
|
objectStorageUseProxy: "Usar proxy"
|
||||||
|
@ -449,7 +481,8 @@ objectStorageUseProxyDesc: "Se você não usa proxy para conexão de API, desati
|
||||||
objectStorageSetPublicRead: "Definir 'public-read' ao fazer o upload"
|
objectStorageSetPublicRead: "Definir 'public-read' ao fazer o upload"
|
||||||
serverLogs: "Registro do servidor"
|
serverLogs: "Registro do servidor"
|
||||||
deleteAll: "Apagar Tudo"
|
deleteAll: "Apagar Tudo"
|
||||||
showFixedPostForm: "Exibir o formulário de postagem na parte superior da linha do tempo"
|
showFixedPostForm: "Exibir o formulário de postagem na parte superior da linha do
|
||||||
|
tempo"
|
||||||
newNoteRecived: "Nova nota recebida"
|
newNoteRecived: "Nova nota recebida"
|
||||||
sounds: "Sons"
|
sounds: "Sons"
|
||||||
listen: "Ouvir"
|
listen: "Ouvir"
|
||||||
|
@ -618,7 +651,8 @@ _pages:
|
||||||
_dailyRannum:
|
_dailyRannum:
|
||||||
arg1: "Valor mínimo"
|
arg1: "Valor mínimo"
|
||||||
arg2: "Valor máximo"
|
arg2: "Valor máximo"
|
||||||
dailyRandomPick: "Escolher aleatoriamente de uma lista (Muda uma vez por dia para cada usuário)"
|
dailyRandomPick: "Escolher aleatoriamente de uma lista (Muda uma vez por dia
|
||||||
|
para cada usuário)"
|
||||||
_dailyRandomPick:
|
_dailyRandomPick:
|
||||||
arg1: "Listas"
|
arg1: "Listas"
|
||||||
seedRandom: "Aleatório (com semente)"
|
seedRandom: "Aleatório (com semente)"
|
||||||
|
@ -634,7 +668,8 @@ _pages:
|
||||||
_seedRandomPick:
|
_seedRandomPick:
|
||||||
arg1: "Semente"
|
arg1: "Semente"
|
||||||
arg2: "Listas"
|
arg2: "Listas"
|
||||||
DRPWPM: "Escolher aleatoriamente de uma lista ponderada (Muda uma vez por dia para cada usuário)"
|
DRPWPM: "Escolher aleatoriamente de uma lista ponderada (Muda uma vez por dia
|
||||||
|
para cada usuário)"
|
||||||
_DRPWPM:
|
_DRPWPM:
|
||||||
arg1: "Lista de texto"
|
arg1: "Lista de texto"
|
||||||
pick: "Escolhe a partir da lista"
|
pick: "Escolhe a partir da lista"
|
||||||
|
@ -665,7 +700,8 @@ _pages:
|
||||||
_for:
|
_for:
|
||||||
arg1: "Número de repetições"
|
arg1: "Número de repetições"
|
||||||
arg2: "Ação"
|
arg2: "Ação"
|
||||||
typeError: "Espaço {slot} aceita valores de tipo \"{expect}\", mas o valor dado é do tipo \"{actual}\"!"
|
typeError: "Espaço {slot} aceita valores de tipo \"{expect}\", mas o valor dado
|
||||||
|
é do tipo \"{actual}\"!"
|
||||||
thereIsEmptySlot: "O espaço {slot} está vazio!"
|
thereIsEmptySlot: "O espaço {slot} está vazio!"
|
||||||
types:
|
types:
|
||||||
string: "Texto"
|
string: "Texto"
|
||||||
|
@ -730,3 +766,5 @@ _deck:
|
||||||
list: "Listas"
|
list: "Listas"
|
||||||
mentions: "Menções"
|
mentions: "Menções"
|
||||||
direct: "Notas diretas"
|
direct: "Notas diretas"
|
||||||
|
editNote: Editar post
|
||||||
|
edited: Editado a {date} às {time}
|
||||||
|
|
|
@ -2044,7 +2044,7 @@ cannotUploadBecauseExceedsFileSizeLimit: Этот файл не может бы
|
||||||
apps: Приложения
|
apps: Приложения
|
||||||
silenceThisInstance: Заглушить сервер
|
silenceThisInstance: Заглушить сервер
|
||||||
silencedInstances: Заглушенные серверы
|
silencedInstances: Заглушенные серверы
|
||||||
editNote: Редактировать заметку
|
editNote: Редактировать пост
|
||||||
edited: 'Редактировано в {date} {time}'
|
edited: 'Редактировано в {date} {time}'
|
||||||
deleted: Удалённое
|
deleted: Удалённое
|
||||||
removeReaction: Удалить вашу реакцию
|
removeReaction: Удалить вашу реакцию
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
---
|
|
||||||
_lang_: "ภาษาไทย"
|
_lang_: "ภาษาไทย"
|
||||||
headlineFirefish: "เชื่อมต่อเครือข่ายโดยโน้ต"
|
headlineFirefish: "เชื่อมต่อเครือข่ายโดยโน้ต"
|
||||||
introFirefish: "ยินดีต้อนรับจ้าาา! Firefish เป็นบริการไมโครบล็อกโอเพ่นซอร์ส แบบการกระจายอำนาจ\nสร้าง \"โน้ต\" เพื่อแบ่งปันความคิดของคุณกับทุกคนรอบตัวคุณกันเถอะ 📡\nด้วยการ \"รีแอคชั่นผู้คน\" คุณยังสามารถแสดงความรู้สึกของคุณเกี่ยวกับบันทึกของทุกคนได้อย่างรวดเร็ว 👍\n\nแล้วมาท่องสำรวจโลกใบใหม่กันเถอะ! 🚀"
|
introFirefish: "ยินดีต้อนรับค่ะ/ครับ! Firefish เป็นแพลตฟอร์มโซเชียลมีเดียแบบโอเพ่นซอร์สที่มีการกระจายอำนาจซึ่งให้บริการฟรีตลอดไป!
|
||||||
|
🚀"
|
||||||
monthAndDay: "{เดือน}/{วัน}"
|
monthAndDay: "{เดือน}/{วัน}"
|
||||||
search: "ค้นหา"
|
search: "ค้นหา"
|
||||||
notifications: "การเเจ้งเตือน"
|
notifications: "การเเจ้งเตือน"
|
||||||
username: "ชื่อผู้ใช้"
|
username: "ชื่อผู้ใช้"
|
||||||
password: "รหัสผ่าน"
|
password: "รหัสผ่าน"
|
||||||
forgotPassword: "ลืมรหัสผ่าน?"
|
forgotPassword: "ลืมรหัสผ่านอ่ะ"
|
||||||
fetchingAsApObject: "กำลังดึงข้อมูล จาก เฟดิเวิร์ส"
|
fetchingAsApObject: "กำลังดึงข้อมูล จาก เฟดิเวิร์ส"
|
||||||
ok: "ตกลง"
|
ok: "ตกลง"
|
||||||
gotIt: "เข้าใจแล้ว !"
|
gotIt: "เข้าใจแล้ว !"
|
||||||
cancel: "ยกเลิก"
|
cancel: "ยกเลิก"
|
||||||
enterUsername: "ใส่ชื่อผู้ใช้"
|
enterUsername: "ใส่ชื่อผู้ใช้"
|
||||||
renotedBy: "รีโน้ตโดย {ผู้ใช้}"
|
renotedBy: "บูตเตอร์โดย {user}"
|
||||||
noNotes: "ไม่มีโน้ต"
|
noNotes: "ไม่มีโพสต์"
|
||||||
noNotifications: "ไม่มีการแจ้งเตือน"
|
noNotifications: "ไม่มีการแจ้งเตือน"
|
||||||
instance: "ตัวอย่าง"
|
instance: "เซิฟเวอร์"
|
||||||
settings: "การตั้งค่า"
|
settings: "การตั้งค่า"
|
||||||
basicSettings: "การตั้งค่าพื้นฐาน"
|
basicSettings: "การตั้งค่าพื้นฐาน"
|
||||||
otherSettings: "การตั้งค่าอื่นๆ"
|
otherSettings: "การตั้งค่าอื่นๆ"
|
||||||
|
@ -44,7 +44,8 @@ copyContent: "คัดลอกเนื้อหา"
|
||||||
copyLink: "คัดลอกลิงก์"
|
copyLink: "คัดลอกลิงก์"
|
||||||
delete: "ลบ"
|
delete: "ลบ"
|
||||||
deleteAndEdit: "ลบและแก้ไข"
|
deleteAndEdit: "ลบและแก้ไข"
|
||||||
deleteAndEditConfirm: "นายแน่ใจแล้วเหรอ? ว่าต้องการลบโน้ตนี้และแก้ไข คุณอาจจะสูญเสียการโต้ตอบ, โน้ต, และการตอบกลับทั้งหมดได้นะ"
|
deleteAndEditConfirm: "คุณแน่ใจแล้วเหรอว่าต้องการลบโพสต์นี้และแก้ไข? คุณอาจจะสูญเสียการโต้ตอบ,
|
||||||
|
โพสต์, และการตอบกลับทั้งหมดได้นะ"
|
||||||
addToList: "เพิ่มในลิสต์"
|
addToList: "เพิ่มในลิสต์"
|
||||||
sendMessage: "ส่งข้อความ"
|
sendMessage: "ส่งข้อความ"
|
||||||
copyUsername: "คัดลอกชื่อผู้ใช้"
|
copyUsername: "คัดลอกชื่อผู้ใช้"
|
||||||
|
@ -58,30 +59,31 @@ receiveFollowRequest: "คำขอผู้ติดตามที่ได้
|
||||||
followRequestAccepted: "ผู้ติดตามได้ตอบรับคำขอร้องของคุณแล้ว"
|
followRequestAccepted: "ผู้ติดตามได้ตอบรับคำขอร้องของคุณแล้ว"
|
||||||
mention: "กล่าวถึง"
|
mention: "กล่าวถึง"
|
||||||
mentions: "พูดถึง"
|
mentions: "พูดถึง"
|
||||||
directNotes: "ไดเร็คโน้ต"
|
directNotes: "ไดเร็คข้อความ"
|
||||||
importAndExport: "นำเข้า / ส่งออก"
|
importAndExport: "นำเข้า / ส่งออก"
|
||||||
import: "การนำเข้า"
|
import: "การนำเข้า"
|
||||||
export: "การนำออก"
|
export: "การนำออก"
|
||||||
files: "ไฟล์"
|
files: "ไฟล์"
|
||||||
download: "ดาวน์โหลด"
|
download: "ดาวน์โหลด"
|
||||||
driveFileDeleteConfirm: "นายแน่ใจแล้วหรอ? ว่าต้องการลบไฟล์ \"{name}\" โน้ตย่อที่แนบมากับไฟล์นี้ก็จะถูกลบด้วยนะ"
|
driveFileDeleteConfirm: "คุณแน่ใจแล้วหรอว่าต้องการลบไฟล์ \"{name}\"? โพสต์ย่อที่แนบมากับไฟล์นี้ก็จะถูกลบด้วยนะ"
|
||||||
unfollowConfirm: "นายแน่ใจแล้วหรอว่าต้องการเลิกติดตาม {name}?"
|
unfollowConfirm: "คุณแน่ใจแล้วหรอว่าต้องการเลิกติดตาม {name}?"
|
||||||
exportRequested: "เมื่อคุณได้ร้องขอการส่งออก อาจจะต้องใช้เวลาสักครู่ และจะถูกเพิ่มในไดรฟ์ของคุณเมื่อเสร็จสิ้นแล้ว"
|
exportRequested: "เมื่อคุณได้ร้องขอการส่งออก อาจจะต้องใช้เวลาสักครู่ และจะถูกเพิ่มในไดรฟ์ของคุณเมื่อเสร็จสิ้นแล้ว"
|
||||||
importRequested: "เมื่อคุณได้ร้องขอการนำเข้า อาจจะต้องใช้เวลาสักครู่นะ"
|
importRequested: "เมื่อคุณได้ร้องขอการนำเข้า อาจจะต้องใช้เวลาสักครู่นะ"
|
||||||
lists: "รายการ"
|
lists: "รายการ"
|
||||||
noLists: "คุณไม่มีลิสต์ใดๆนะ"
|
noLists: "คุณไม่มีลิสต์ใดๆนะ"
|
||||||
note: "ตัวโน้ต"
|
note: "โพสต์"
|
||||||
notes: "หมายเหตุ"
|
notes: "โพสต์"
|
||||||
following: "กำลังติดตาม"
|
following: "กำลังติดตาม"
|
||||||
followers: "ผู้ติดตาม"
|
followers: "ผู้ติดตาม"
|
||||||
followsYou: "ติดตามคุณ"
|
followsYou: "ติดตามคุณ"
|
||||||
createList: "สร้างลิสต์"
|
createList: "สร้างลิสต์"
|
||||||
manageLists: "จัดการลิสต์"
|
manageLists: "จัดการลิสต์"
|
||||||
error: "ผิดพลาด!"
|
error: "ผิดพลาด"
|
||||||
somethingHappened: "อุ๊ย ! มีอะไรบางอย่างผิดพลาด"
|
somethingHappened: "อุ๊ย ! มีอะไรบางอย่างผิดพลาด"
|
||||||
retry: "ลองใหม่อีกครั้ง"
|
retry: "ลองใหม่อีกครั้ง"
|
||||||
pageLoadError: "เกิดข้อผิดพลาดในการโหลดหน้านี้"
|
pageLoadError: "เกิดข้อผิดพลาดในการโหลดหน้านี้"
|
||||||
pageLoadErrorDescription: "โดยปกติแล้วมักจะเกิดจากข้อผิดพลาดของเครือข่ายหรือแคชของเบราว์เซอร์ ลองล้างแคชแล้วลองใหม่อีกครั้งหลังจากรอสักครู่ "
|
pageLoadErrorDescription: "โดยปกติแล้วมักจะเกิดจากข้อผิดพลาดของเครือข่ายหรือแคชของเบราว์เซอร์
|
||||||
|
ลองล้างแคชแล้วลองใหม่อีกครั้งหลังจากรอสักครู่นะ"
|
||||||
serverIsDead: "เซิร์ฟเวอร์นี้ไม่มีการตอบสนอง ได้โปรดกรุณารอสักครู่แล้วลองใหม่อีกครั้งนะ"
|
serverIsDead: "เซิร์ฟเวอร์นี้ไม่มีการตอบสนอง ได้โปรดกรุณารอสักครู่แล้วลองใหม่อีกครั้งนะ"
|
||||||
youShouldUpgradeClient: "หากต้องการดูหน้านี้ได้โปรดกรุณา รีเซ็ตเพื่ออัปเดตไคลเอ็นต์ของคุณนะ"
|
youShouldUpgradeClient: "หากต้องการดูหน้านี้ได้โปรดกรุณา รีเซ็ตเพื่ออัปเดตไคลเอ็นต์ของคุณนะ"
|
||||||
enterListName: "ใส่ชื่อสำหรับรายการลิสต์"
|
enterListName: "ใส่ชื่อสำหรับรายการลิสต์"
|
||||||
|
@ -89,18 +91,18 @@ privacy: "ความเป็นส่วนตัว"
|
||||||
makeFollowManuallyApprove: "ติดตามคำขอที่ต้องได้รับการอนุมัติ"
|
makeFollowManuallyApprove: "ติดตามคำขอที่ต้องได้รับการอนุมัติ"
|
||||||
defaultNoteVisibility: "การมองเห็นที่เป็นค่าเริ่มต้น"
|
defaultNoteVisibility: "การมองเห็นที่เป็นค่าเริ่มต้น"
|
||||||
follow: "กำลังติดตาม"
|
follow: "กำลังติดตาม"
|
||||||
followRequest: "ส่งคำขอติดตาม"
|
followRequest: "คำขอติดตาม"
|
||||||
followRequests: "ติดตามการร้องขอ"
|
followRequests: "ติดตามการร้องขอ"
|
||||||
unfollow: "เลิกติดตาม"
|
unfollow: "เลิกติดตาม"
|
||||||
followRequestPending: "กำลังรอดำเนินการร้องขอติดตาม"
|
followRequestPending: "กำลังรอดำเนินการร้องขอติดตาม"
|
||||||
enterEmoji: "ใส่อีโมจิ"
|
enterEmoji: "ใส่อีโมจิ"
|
||||||
renote: "รีโน้ต"
|
renote: "บูสต์"
|
||||||
unrenote: "เลิกรีโน้ต"
|
unrenote: "เลิกบูสต์"
|
||||||
renoted: "รีโน้ตเอาไว้"
|
renoted: "บูสต์แล้ว"
|
||||||
cantRenote: "โพสต์นี้ไม่สามารถรีโน้ตไว้ใหม่ได้นะ"
|
cantRenote: "โพสต์นี้ไม่สามารถบูสต์ใหม่ได้"
|
||||||
cantReRenote: "ไม่สามารถรีโน้ตเอาไว้ใหม่ได้นะ"
|
cantReRenote: "ไม่สามารถบูสต์ไว้ใหม่ได้"
|
||||||
quote: "อ้างคำพูด"
|
quote: "อ้างคำพูด"
|
||||||
pinnedNote: "โน้ตที่ปักหมุดเอาไว้"
|
pinnedNote: "โพสต์ที่ปักหมุดแล้ว"
|
||||||
pinned: "ปักหมุดไปยังโปรไฟล์"
|
pinned: "ปักหมุดไปยังโปรไฟล์"
|
||||||
you: "ตัวเอง"
|
you: "ตัวเอง"
|
||||||
clickToShow: "คลิกเพื่อแสดง"
|
clickToShow: "คลิกเพื่อแสดง"
|
||||||
|
@ -109,7 +111,7 @@ add: "เพิ่ม"
|
||||||
reaction: "รีแอคชั่น"
|
reaction: "รีแอคชั่น"
|
||||||
reactionSetting: "รีแอคชั่นไปยังแสดงผลในตัวเลือกการรีแอคชั่น"
|
reactionSetting: "รีแอคชั่นไปยังแสดงผลในตัวเลือกการรีแอคชั่น"
|
||||||
reactionSettingDescription2: "กดลากเพื่อจัดลำดับใหม่ กดคลิกเพื่อลบ กด \"+\" เพื่อเพิ่ม"
|
reactionSettingDescription2: "กดลากเพื่อจัดลำดับใหม่ กดคลิกเพื่อลบ กด \"+\" เพื่อเพิ่ม"
|
||||||
rememberNoteVisibility: "จดจำการตั้งค่าการมองเห็นตัวโน้ต"
|
rememberNoteVisibility: "จดจำการตั้งค่าการมองเห็นโพสต์"
|
||||||
attachCancel: "ลบไฟล์ออกที่แนบมา"
|
attachCancel: "ลบไฟล์ออกที่แนบมา"
|
||||||
markAsSensitive: "ทำเครื่องหมายว่าละเอียดอ่อน"
|
markAsSensitive: "ทำเครื่องหมายว่าละเอียดอ่อน"
|
||||||
unmarkAsSensitive: "ยกเลิกทำเครื่องหมายเป็น NSFW"
|
unmarkAsSensitive: "ยกเลิกทำเครื่องหมายเป็น NSFW"
|
||||||
|
@ -120,11 +122,11 @@ block: "บล็อค"
|
||||||
unblock: "เลิกปิดกั้น"
|
unblock: "เลิกปิดกั้น"
|
||||||
suspend: "ถูกระงับ"
|
suspend: "ถูกระงับ"
|
||||||
unsuspend: "ยกเลิกระงับ"
|
unsuspend: "ยกเลิกระงับ"
|
||||||
blockConfirm: "คุณแน่ใจแล้วเหรอ? ว่าต้องการบล็อกบัญชีนี้"
|
blockConfirm: "คุณแน่ใจแล้วเหรอ ว่าต้องการบล็อกบัญชีนี้?"
|
||||||
unblockConfirm: "คุณแน่ใจแล้วเหรอ? ว่าต้องการปลดบล็อคบัญชีนี้"
|
unblockConfirm: "คุณแน่ใจแล้วเหรอ ว่าต้องการปลดบล็อคบัญชีนี้?"
|
||||||
suspendConfirm: "นายแน่ใจแล้วเหรอว่าต้องการระงับบัญชีนี้อ่ะ?"
|
suspendConfirm: "คุณแน่ใจแล้วเหรอว่าต้องการระงับบัญชีนี้อ่ะ?"
|
||||||
unsuspendConfirm: "นายแน่ใจแล้วหรอ? ว่าต้องการยกเลิกการระงับบัญชีนี้"
|
unsuspendConfirm: "คุณแน่ใจแล้วหรอว่าต้องการยกเลิกการระงับบัญชีนี้?"
|
||||||
selectList: "เลือกรายการ (Automatic Translation)"
|
selectList: "เลือกรายการ"
|
||||||
selectAntenna: "เลือกเสาอากาศ"
|
selectAntenna: "เลือกเสาอากาศ"
|
||||||
selectWidget: "เลือกวิดเจ็ต"
|
selectWidget: "เลือกวิดเจ็ต"
|
||||||
editWidgets: "แก้ไขวิดเจ็ต"
|
editWidgets: "แก้ไขวิดเจ็ต"
|
||||||
|
@ -137,13 +139,17 @@ emojiUrl: "อิโมจิ URL"
|
||||||
addEmoji: "แทรกอีโมจิ"
|
addEmoji: "แทรกอีโมจิ"
|
||||||
settingGuide: "การตั้งค่าที่แนะนำ"
|
settingGuide: "การตั้งค่าที่แนะนำ"
|
||||||
cacheRemoteFiles: "แคชไฟล์ระยะไกล"
|
cacheRemoteFiles: "แคชไฟล์ระยะไกล"
|
||||||
cacheRemoteFilesDescription: "เมื่อปิดใช้งานการตั้งค่านี้ ไฟล์ระยะไกลนั้นจะถูกโหลดโดยตรงจากอินสแตนซ์ระยะไกล แต่กรณีการปิดใช้งานนี้จะช่วยลดปริมาณการใช้พื้นที่จัดเก็บข้อมูล แต่เพิ่มปริมาณการใช้งาน เพราะเนื่องจากจะไม่มีการสร้างภาพขนาดย่อ"
|
cacheRemoteFilesDescription: "เมื่อปิดใช้งานการตั้งค่านี้ ไฟล์ระยะไกลนั้นจะถูกโหลดโดยตรงจากระยะไกลเซิฟเวอร์
|
||||||
|
แต่กรณีการปิดใช้งานนี้จะช่วยลดปริมาณการใช้พื้นที่จัดเก็บข้อมูล แต่เพิ่มปริมาณการใช้งาน
|
||||||
|
เพราะเนื่องจากจะไม่มีการสร้างภาพขนาดย่อ"
|
||||||
flagAsBot: "ทำเครื่องหมายบอกว่าบัญชีนี้เป็นบอท"
|
flagAsBot: "ทำเครื่องหมายบอกว่าบัญชีนี้เป็นบอท"
|
||||||
flagAsBotDescription: "การเปิดใช้งานตัวเลือกนี้หากบัญชีนี้ถูกควบคุมโดยนักเขียนโปรแกรม หรือ ถ้าหากเปิดใช้งาน มันจะทำหน้าที่เป็นแฟล็กสำหรับนักพัฒนารายอื่นๆ และเพื่อป้องกันการโต้ตอบแบบไม่มีที่สิ้นสุดกับบอทตัวอื่นๆ และยังสามารถปรับเปลี่ยนระบบภายในของ Firefish เพื่อปฏิบัติต่อบัญชีนี้เป็นบอท"
|
flagAsBotDescription: "การเปิดใช้งานตัวเลือกนี้หากบัญชีนี้ถูกควบคุมโดยนักเขียนโปรแกรม
|
||||||
|
หรือ ถ้าหากเปิดใช้งาน มันจะทำหน้าที่เป็นแฟล็กสำหรับนักพัฒนารายอื่นๆ และเพื่อป้องกันการโต้ตอบแบบไม่มีที่สิ้นสุดกับบอทตัวอื่นๆ
|
||||||
|
และยังสามารถปรับเปลี่ยนระบบภายในของ Firefish เพื่อปฏิบัติต่อบัญชีนี้เป็นบอท"
|
||||||
flagAsCat: "ทำเครื่องหมายบอกว่าบัญชีนี้เป็นแมว"
|
flagAsCat: "ทำเครื่องหมายบอกว่าบัญชีนี้เป็นแมว"
|
||||||
flagAsCatDescription: "การเปิดใช้งานตัวเลือกนี้เพื่อทำเครื่องหมายบอกว่าบัญชีนี้เป็นแมว"
|
flagAsCatDescription: "คุณจะได้รับหูแมวและพูดเหมือนแมวนะ!"
|
||||||
flagShowTimelineReplies: "แสดงตอบกลับ ในไทม์ไลน์"
|
flagShowTimelineReplies: "แสดงตอบกลับ ในไทม์ไลน์"
|
||||||
flagShowTimelineRepliesDescription: "แสดงการตอบกลับของผู้ใช้งานไปยังโน้ตของผู้ใช้งานรายอื่นๆในไทม์ไลน์หากได้เปิดเอาไว้"
|
flagShowTimelineRepliesDescription: "แสดงการตอบกลับของผู้ใช้งานไปยังโพสต์ของผู้ใช้งานรายอื่นๆในไทม์ไลน์หากได้เปิดเอาไว้"
|
||||||
autoAcceptFollowed: "อนุมัติคำขอติดตามโดยอัตโนมัติทันที จากผู้ใช้งานที่คุณกำลังติดตาม"
|
autoAcceptFollowed: "อนุมัติคำขอติดตามโดยอัตโนมัติทันที จากผู้ใช้งานที่คุณกำลังติดตาม"
|
||||||
addAccount: "เพิ่มบัญชี"
|
addAccount: "เพิ่มบัญชี"
|
||||||
loginFailed: "การเข้าสู่ระบบไม่สำเร็จ"
|
loginFailed: "การเข้าสู่ระบบไม่สำเร็จ"
|
||||||
|
@ -155,15 +161,17 @@ removeWallpaper: "นำวอลเปเปอร์ออก"
|
||||||
searchWith: "ค้นหา: {q}"
|
searchWith: "ค้นหา: {q}"
|
||||||
youHaveNoLists: "รายการนี้ว่างเปล่า"
|
youHaveNoLists: "รายการนี้ว่างเปล่า"
|
||||||
followConfirm: "คุณแน่ใจแล้วหรอว่าต้องการที่จะติดตาม {name}?"
|
followConfirm: "คุณแน่ใจแล้วหรอว่าต้องการที่จะติดตาม {name}?"
|
||||||
proxyAccount: "บัญชี พร็อกซี่"
|
proxyAccount: "บัญชีพร็อกซี"
|
||||||
proxyAccountDescription: "บัญชีพร็อกซี่ คือ บัญชีที่จะทำหน้าที่เป็นผู้ติดตามระยะไกลสำหรับผู้ใช้งานที่อยู่ภายใต้ด้วยเงื่อนไขบางอย่าง ยกตัวอย่าง เช่น เมื่อมีผู้ใช้งานนั้นได้เพิ่มผู้ใช้งานจากระยะไกลลงในรายการ แต่กิจกรรมของผู้ใช้ในระยะไกลนั้นจะไม่ถูกส่งไปยังอินสแตนซ์หากไม่มีผู้ใช้งานในพื้นที่ติดตามผู้ใช้รายนั้น ดังนั้นบัญชีพร็อกซีนี้จะติดตามแทน"
|
proxyAccountDescription: "บัญชีพร็อกซี่ คือ บัญชีที่จะทำหน้าที่เป็นผู้ติดตามระยะไกลสำหรับผู้ใช้งานที่อยู่ภายใต้ด้วยเงื่อนไขบางอย่าง
|
||||||
|
ยกตัวอย่าง เช่น เมื่อมีผู้ใช้งานนั้นได้เพิ่มผู้ใช้งานจากระยะไกลลงในรายการ แต่กิจกรรมของผู้ใช้ในระยะไกลนั้นจะไม่ถูกส่งไปยังเซิฟเวอร์
|
||||||
|
หากไม่มีผู้ใช้งานในพื้นที่ติดตามผู้ใช้รายนั้น ดังนั้นบัญชีพร็อกซีนี้จะติดตามแทน"
|
||||||
host: "โฮสต์"
|
host: "โฮสต์"
|
||||||
selectUser: "เลือกผู้ใช้งาน"
|
selectUser: "เลือกผู้ใช้งาน"
|
||||||
recipient: "ผู้รับ"
|
recipient: "ผู้รับ"
|
||||||
annotation: "ความคิดเห็น"
|
annotation: "ความคิดเห็น"
|
||||||
federation: "สหพันธ์"
|
federation: "สหพันธ์"
|
||||||
instances: "ตัวอย่าง"
|
instances: "เซิฟเวอร์"
|
||||||
registeredAt: "จดทะเบียนที่"
|
registeredAt: "จดทะเบียนแล้วที่"
|
||||||
latestRequestSentAt: "ส่งคำขอล่าสุดไปแล้ว"
|
latestRequestSentAt: "ส่งคำขอล่าสุดไปแล้ว"
|
||||||
latestRequestReceivedAt: "ได้รับคำขอล่าสุดไปแล้ว"
|
latestRequestReceivedAt: "ได้รับคำขอล่าสุดไปแล้ว"
|
||||||
latestStatus: "สถานะล่าสุด"
|
latestStatus: "สถานะล่าสุด"
|
||||||
|
@ -186,7 +194,8 @@ instanceInfo: "ข้อมูล อินสแตนซ์"
|
||||||
statistics: "สถิติการใช้งาน"
|
statistics: "สถิติการใช้งาน"
|
||||||
clearQueue: "ล้างคิว"
|
clearQueue: "ล้างคิว"
|
||||||
clearQueueConfirmTitle: "คุณแน่ใจแล้วหรอว่าต้องการที่จะล้างคิว?"
|
clearQueueConfirmTitle: "คุณแน่ใจแล้วหรอว่าต้องการที่จะล้างคิว?"
|
||||||
clearQueueConfirmText: "บันทึกย่อที่ยังไม่ได้ส่งที่เหลืออยู่ในคิวนั้นมักจะ ไม่ถูกรวมเข้าด้วยกัน โดยปกติแล้วไม่จำเป็นต้องดำเนินการนี้"
|
clearQueueConfirmText: "บันทึกย่อที่ยังไม่ได้ส่งที่เหลืออยู่ในคิวนั้นมักจะ ไม่ถูกรวมเข้าด้วยกัน
|
||||||
|
โดยปกติแล้วไม่จำเป็นต้องดำเนินการนี้"
|
||||||
clearCachedFiles: "ล้างแคช"
|
clearCachedFiles: "ล้างแคช"
|
||||||
clearCachedFilesConfirm: "นายแน่ใจแล้วหรอว่าต้องการที่จะลบไฟล์ระยะไกลที่แคชไว้ทั้งหมด?"
|
clearCachedFilesConfirm: "นายแน่ใจแล้วหรอว่าต้องการที่จะลบไฟล์ระยะไกลที่แคชไว้ทั้งหมด?"
|
||||||
blockedInstances: "อินสแตนซ์ที่ ถูกบล็อก"
|
blockedInstances: "อินสแตนซ์ที่ ถูกบล็อก"
|
||||||
|
@ -232,14 +241,15 @@ announcements: "ประกาศ"
|
||||||
imageUrl: "url รูปภาพ"
|
imageUrl: "url รูปภาพ"
|
||||||
remove: "ลบ"
|
remove: "ลบ"
|
||||||
removed: "ถูกลบไปแล้ว"
|
removed: "ถูกลบไปแล้ว"
|
||||||
removeAreYouSure: "นายแน่ใจจริงหรอว่าต้องการที่จะลบออก \"{x}\""
|
removeAreYouSure: "คุณแน่ใจจริงหรอว่าต้องการที่จะลบออก \"{x}\"?"
|
||||||
deleteAreYouSure: "นายแน่ใจจริงหรอว่าต้องการที่จะลบออก \"{x}\""
|
deleteAreYouSure: "คุณแน่ใจหรอว่าต้องการที่จะลบออก \"{x}\"?"
|
||||||
resetAreYouSure: "รีเซ็ตเลยไหม"
|
resetAreYouSure: "จริงหรอรีเซ็ตเลยไหม?"
|
||||||
saved: "บันทึกแล้ว"
|
saved: "บันทึกแล้ว"
|
||||||
messaging: "แชท"
|
messaging: "แชท"
|
||||||
upload: "อัพโหลด"
|
upload: "อัพโหลด"
|
||||||
keepOriginalUploading: "เก็บภาพต้นฉบับ"
|
keepOriginalUploading: "เก็บภาพต้นฉบับ"
|
||||||
keepOriginalUploadingDescription: "บันทึกรูปภาพที่อัพโหลดต้นฉบับตามที่เป็นอยู่ ถ้าหากปิดอยู่ ระบบจะสร้างเวอร์ชั่นที่จะแสดงบนเว็บเมื่ออัพโหลดนะ"
|
keepOriginalUploadingDescription: "บันทึกรูปภาพที่อัพโหลดต้นฉบับตามที่เป็นอยู่ ถ้าหากปิดอยู่
|
||||||
|
ระบบจะสร้างเวอร์ชั่นที่จะแสดงบนเว็บเมื่ออัพโหลดนะ"
|
||||||
fromDrive: "จากไดรฟ์"
|
fromDrive: "จากไดรฟ์"
|
||||||
fromUrl: "จาก URL"
|
fromUrl: "จาก URL"
|
||||||
uploadFromUrl: "อัพโหลดจาก URL"
|
uploadFromUrl: "อัพโหลดจาก URL"
|
||||||
|
@ -253,7 +263,7 @@ startMessaging: "เริ่มการสนทนา"
|
||||||
nUsersRead: "อ่านโดย {n}"
|
nUsersRead: "อ่านโดย {n}"
|
||||||
agreeTo: "ฉันยอมรับที่จะ {0}"
|
agreeTo: "ฉันยอมรับที่จะ {0}"
|
||||||
tos: "ข้อกำหนดและเงื่อนไข"
|
tos: "ข้อกำหนดและเงื่อนไข"
|
||||||
start: "เริ่มต้นใช้งาน"
|
start: "เริ่มต้น"
|
||||||
home: "หน้าแรก"
|
home: "หน้าแรก"
|
||||||
remoteUserCaution: "เนื่องจากผู้ใช้งานรายนี้นั้น มาจากอินสแตนซ์ระยะไกล ข้อมูลที่แสดงดังกล่าวนั้นอาจจะไม่สมบูรณ์ก็ได้นะ"
|
remoteUserCaution: "เนื่องจากผู้ใช้งานรายนี้นั้น มาจากอินสแตนซ์ระยะไกล ข้อมูลที่แสดงดังกล่าวนั้นอาจจะไม่สมบูรณ์ก็ได้นะ"
|
||||||
activity: "กิจกรรม"
|
activity: "กิจกรรม"
|
||||||
|
@ -334,9 +344,11 @@ bannerUrl: "URL รูปภาพแบนเนอร์"
|
||||||
backgroundImageUrl: "URL ภาพพื้นหลัง"
|
backgroundImageUrl: "URL ภาพพื้นหลัง"
|
||||||
basicInfo: "ข้อมูลเบื้องต้น"
|
basicInfo: "ข้อมูลเบื้องต้น"
|
||||||
pinnedUsers: "ผู้ใช้งานที่ได้รับการปักหมุด"
|
pinnedUsers: "ผู้ใช้งานที่ได้รับการปักหมุด"
|
||||||
pinnedUsersDescription: "ลิสต์ชื่อผู้ใช้โดยคั่นด้วยการขึ้นบรรทัดใหม่เพื่อปักหมุดในแท็บ \"สำรวจ\""
|
pinnedUsersDescription: "ลิสต์ชื่อผู้ใช้โดยคั่นด้วยการขึ้นบรรทัดใหม่เพื่อปักหมุดในแท็บ
|
||||||
|
\"สำรวจ\""
|
||||||
pinnedPages: "หน้าที่ปักหมุด"
|
pinnedPages: "หน้าที่ปักหมุด"
|
||||||
pinnedPagesDescription: "ป้อนเส้นทางของหน้าที่คุณต้องการตรึงไว้ที่หน้าแรกของอินสแตนซ์นี้ โดยคั่นด้วยตัวแบ่งบรรทัด"
|
pinnedPagesDescription: "ป้อนเส้นทางของหน้าที่คุณต้องการตรึงไว้ที่หน้าแรกของอินสแตนซ์นี้
|
||||||
|
โดยคั่นด้วยตัวแบ่งบรรทัด"
|
||||||
pinnedClipId: "ID ของคลิปที่จะปักหมุด"
|
pinnedClipId: "ID ของคลิปที่จะปักหมุด"
|
||||||
pinnedNotes: "โน้ตที่ปักหมุดเอาไว้"
|
pinnedNotes: "โน้ตที่ปักหมุดเอาไว้"
|
||||||
hcaptcha: "hCaptcha"
|
hcaptcha: "hCaptcha"
|
||||||
|
@ -347,14 +359,17 @@ recaptcha: "reCAPTCHA"
|
||||||
enableRecaptcha: "เปิดใช้ reCAPTCHA"
|
enableRecaptcha: "เปิดใช้ reCAPTCHA"
|
||||||
recaptchaSiteKey: "คีย์ไซต์"
|
recaptchaSiteKey: "คีย์ไซต์"
|
||||||
recaptchaSecretKey: "คีย์ลับ"
|
recaptchaSecretKey: "คีย์ลับ"
|
||||||
avoidMultiCaptchaConfirm: "การใช้ระบบ Captcha หลายระบบอาจทำให้เกิดการรบกวนหรืออาจจะเกิดข้อผิดพลาดได้ หากต้องการที่จะปิดการใช้งานระบบ Captcha อื่น ๆ แนะนำให้ปิดตัวอื่นๆก่อน ถ้าหากคุณต้องการให้เปิดใช้งานต่อไป ให้ กด ยกเลิก"
|
avoidMultiCaptchaConfirm: "การใช้ระบบ Captcha หลายระบบอาจทำให้เกิดการรบกวนหรืออาจจะเกิดข้อผิดพลาดได้
|
||||||
|
หากต้องการที่จะปิดการใช้งานระบบ Captcha อื่น ๆ แนะนำให้ปิดตัวอื่นๆก่อน ถ้าหากคุณต้องการให้เปิดใช้งานต่อไป
|
||||||
|
ให้ กด ยกเลิก"
|
||||||
antennas: "เสาอากาศ"
|
antennas: "เสาอากาศ"
|
||||||
manageAntennas: "จัดการเสาอากาศ"
|
manageAntennas: "จัดการเสาอากาศ"
|
||||||
name: "ชื่อ"
|
name: "ชื่อ"
|
||||||
antennaSource: "แหล่งเสาอากาศ"
|
antennaSource: "แหล่งเสาอากาศ"
|
||||||
antennaKeywords: "คีย์เวิร์ดที่ควรฟัง"
|
antennaKeywords: "คีย์เวิร์ดที่ควรฟัง"
|
||||||
antennaExcludeKeywords: "คีย์เวิร์ดที่จะยกเว้น"
|
antennaExcludeKeywords: "คีย์เวิร์ดที่จะยกเว้น"
|
||||||
antennaKeywordsDescription: "คั่นด้วยช่องว่างสำหรับเงื่อนไข AND หรือด้วยการขึ้นบรรทัดใหม่สำหรับเงื่อนไข OR นะ"
|
antennaKeywordsDescription: "คั่นด้วยช่องว่างสำหรับเงื่อนไข AND หรือด้วยการขึ้นบรรทัดใหม่สำหรับเงื่อนไข
|
||||||
|
OR นะ"
|
||||||
notifyAntenna: "แจ้งเตือนเกี่ยวกับโน้ตใหม่"
|
notifyAntenna: "แจ้งเตือนเกี่ยวกับโน้ตใหม่"
|
||||||
withFileAntenna: "เฉพาะโน้ตที่มีไฟล์"
|
withFileAntenna: "เฉพาะโน้ตที่มีไฟล์"
|
||||||
enableServiceworker: "เปิดใช้งาน การแจ้งเตือนแบบพุชสำหรับเบราว์เซอร์ของคุณ"
|
enableServiceworker: "เปิดใช้งาน การแจ้งเตือนแบบพุชสำหรับเบราว์เซอร์ของคุณ"
|
||||||
|
@ -433,7 +448,8 @@ invitationCode: "รหัสคำเชิญ"
|
||||||
checking: "Checking"
|
checking: "Checking"
|
||||||
available: "พร้อมใช้งาน"
|
available: "พร้อมใช้งาน"
|
||||||
unavailable: "ไม่พร้อมใช้"
|
unavailable: "ไม่พร้อมใช้"
|
||||||
usernameInvalidFormat: "คุณสามารถใช้อักษรตัวพิมพ์ใหญ่และตัวพิมพ์เล็ก ตัวเลข และขีดล่างได้นะ ( a-z , A-Z , 0-9 , รวมไปถึงอักษรพิเศษเช่น + * / , . - อื่นๆเป็นต้น )"
|
usernameInvalidFormat: "คุณสามารถใช้อักษรตัวพิมพ์ใหญ่และตัวพิมพ์เล็ก ตัวเลข และขีดล่างได้นะ
|
||||||
|
( a-z , A-Z , 0-9 , รวมไปถึงอักษรพิเศษเช่น + * / , . - อื่นๆเป็นต้น )"
|
||||||
tooShort: "สั้นเกินไปนะ"
|
tooShort: "สั้นเกินไปนะ"
|
||||||
tooLong: "ยาวเกินไปนะ"
|
tooLong: "ยาวเกินไปนะ"
|
||||||
weakPassword: "รหัสผ่าน แย่มาก"
|
weakPassword: "รหัสผ่าน แย่มาก"
|
||||||
|
@ -483,19 +499,26 @@ showFeaturedNotesInTimeline: "แสดงโน้ตเด่นในไท
|
||||||
objectStorage: "อ็อบเจ็กต์ ที่จัดเก็บ"
|
objectStorage: "อ็อบเจ็กต์ ที่จัดเก็บ"
|
||||||
useObjectStorage: "ใช้ อ็อบเจ็กต์ ที่จัดเก็บ"
|
useObjectStorage: "ใช้ อ็อบเจ็กต์ ที่จัดเก็บ"
|
||||||
objectStorageBaseUrl: "URL ฐาน"
|
objectStorageBaseUrl: "URL ฐาน"
|
||||||
objectStorageBaseUrlDesc: "URL ที่ใช้เป็นข้อมูลอ้างอิง ระบุ URL ของ CDN หรือ Proxy ถ้าหากคุณใช้อย่างใดอย่างหนึ่ง\n สำหรับการใช้งาน S3 'https://<bucket>.s3.amazonaws.com' และสำหรับ GCS หรือบริการที่เทียบเท่าใช้ 'https://storage.googleapis.com/<bucket>', เป็นต้น"
|
objectStorageBaseUrlDesc: "URL ที่ใช้เป็นข้อมูลอ้างอิง ระบุ URL ของ CDN หรือ Proxy
|
||||||
|
ถ้าหากคุณใช้อย่างใดอย่างหนึ่ง\n สำหรับการใช้งาน S3 'https://<bucket>.s3.amazonaws.com'
|
||||||
|
และสำหรับ GCS หรือบริการที่เทียบเท่าใช้ 'https://storage.googleapis.com/<bucket>',
|
||||||
|
เป็นต้น"
|
||||||
objectStorageBucket: "Bucket"
|
objectStorageBucket: "Bucket"
|
||||||
objectStorageBucketDesc: "โปรดระบุชื่อที่เก็บข้อมูลที่ใช้กับผู้ให้บริการของคุณ"
|
objectStorageBucketDesc: "โปรดระบุชื่อที่เก็บข้อมูลที่ใช้กับผู้ให้บริการของคุณ"
|
||||||
objectStoragePrefix: "คำนำหน้า"
|
objectStoragePrefix: "คำนำหน้า"
|
||||||
objectStoragePrefixDesc: "ไฟล์ทั้งหมดจะถูกเก็บไว้ภายใต้ไดเร็กทอรีที่มีคำนำหน้านี้นะ"
|
objectStoragePrefixDesc: "ไฟล์ทั้งหมดจะถูกเก็บไว้ภายใต้ไดเร็กทอรีที่มีคำนำหน้านี้นะ"
|
||||||
objectStorageEndpoint: "ปลายทาง"
|
objectStorageEndpoint: "ปลายทาง"
|
||||||
objectStorageEndpointDesc: "เว้นว่างไว้หากคุณใช้ AWS S3 หรือระบุปลายทางเป็น '<host>' หรือ '<host>:<port>' ทั้งนี้ขึ้นอยู่กับผู้ให้บริการที่คุณใช้อยู่ด้วย"
|
objectStorageEndpointDesc: "เว้นว่างไว้หากคุณใช้ AWS S3 หรือระบุปลายทางเป็น '<host>'
|
||||||
|
หรือ '<host>:<port>' ทั้งนี้ขึ้นอยู่กับผู้ให้บริการที่คุณใช้อยู่ด้วย"
|
||||||
objectStorageRegion: "ภูมิภาค"
|
objectStorageRegion: "ภูมิภาค"
|
||||||
objectStorageRegionDesc: "ระบุภูมิภาค เช่น 'xx-east-1' ถ้าหากบริการของคุณไม่ได้แยกความแตกต่างระหว่างภูมิภาคก็ให้ เว้นว่างไว้หรือป้อน 'us-east-1'"
|
objectStorageRegionDesc: "ระบุภูมิภาค เช่น 'xx-east-1' ถ้าหากบริการของคุณไม่ได้แยกความแตกต่างระหว่างภูมิภาคก็ให้
|
||||||
|
เว้นว่างไว้หรือป้อน 'us-east-1'"
|
||||||
objectStorageUseSSL: "ใช้ SSL"
|
objectStorageUseSSL: "ใช้ SSL"
|
||||||
objectStorageUseSSLDesc: "ปิดการทำงานนี้ไว้ ถ้าหากคุณจะไม่ใช้ HTTPS สำหรับการเชื่อมต่อ API"
|
objectStorageUseSSLDesc: "ปิดการทำงานนี้ไว้ ถ้าหากคุณจะไม่ใช้ HTTPS สำหรับการเชื่อมต่อ
|
||||||
|
API"
|
||||||
objectStorageUseProxy: "เชื่อมต่อผ่านพร็อกซี"
|
objectStorageUseProxy: "เชื่อมต่อผ่านพร็อกซี"
|
||||||
objectStorageUseProxyDesc: "ปิดสิ่งนี้ไว้ถ้าหากคุณจะไม่ใช้ Proxy สำหรับการเชื่อมต่อ API"
|
objectStorageUseProxyDesc: "ปิดสิ่งนี้ไว้ถ้าหากคุณจะไม่ใช้ Proxy สำหรับการเชื่อมต่อ
|
||||||
|
API"
|
||||||
objectStorageSetPublicRead: "ตั้งค่า \"public-read\" ในการอัปโหลด"
|
objectStorageSetPublicRead: "ตั้งค่า \"public-read\" ในการอัปโหลด"
|
||||||
serverLogs: "บันทึกของเซิร์ฟเวอร์"
|
serverLogs: "บันทึกของเซิร์ฟเวอร์"
|
||||||
deleteAll: "ลบทั้งหมด"
|
deleteAll: "ลบทั้งหมด"
|
||||||
|
@ -523,7 +546,8 @@ sort: "เรียงลำดับ"
|
||||||
ascendingOrder: "เรียงจากน้อยไปมาก"
|
ascendingOrder: "เรียงจากน้อยไปมาก"
|
||||||
descendingOrder: "เรียงจากมากไปน้อย"
|
descendingOrder: "เรียงจากมากไปน้อย"
|
||||||
scratchpad: "กระดานทดลอง"
|
scratchpad: "กระดานทดลอง"
|
||||||
scratchpadDescription: "Scratchpad เป็นการจัดเตรียมสภาพแวดล้อมสำหรับการทดลอง AiScript แต่คุณสามารถเขียน ดำเนินการ และตรวจสอบผลลัพธ์ของการโต้ตอบกับ Firefish มันได้ด้วยนะ"
|
scratchpadDescription: "Scratchpad เป็นการจัดเตรียมสภาพแวดล้อมสำหรับการทดลอง AiScript
|
||||||
|
แต่คุณสามารถเขียน ดำเนินการ และตรวจสอบผลลัพธ์ของการโต้ตอบกับ Firefish มันได้ด้วยนะ"
|
||||||
output: "เอาท์พุต"
|
output: "เอาท์พุต"
|
||||||
script: "สคริปต์"
|
script: "สคริปต์"
|
||||||
disablePagesScript: "ปิดการใช้งาน AiScript บนเพจ"
|
disablePagesScript: "ปิดการใช้งาน AiScript บนเพจ"
|
||||||
|
@ -531,11 +555,14 @@ updateRemoteUser: "อัปเดตข้อมูลผู้ใช้งา
|
||||||
deleteAllFiles: "ลบไฟล์ทั้งหมด"
|
deleteAllFiles: "ลบไฟล์ทั้งหมด"
|
||||||
deleteAllFilesConfirm: "นายแน่ใจแล้วหรอว่าต้องการที่จะลบไฟล์ทั้งหมด?"
|
deleteAllFilesConfirm: "นายแน่ใจแล้วหรอว่าต้องการที่จะลบไฟล์ทั้งหมด?"
|
||||||
removeAllFollowing: "เลิกติดตามผู้ใช้ที่ติดตามทั้งหมด"
|
removeAllFollowing: "เลิกติดตามผู้ใช้ที่ติดตามทั้งหมด"
|
||||||
removeAllFollowingDescription: "การที่คุณดำเนินการนี้จะเลิกติดตามบัญชีทั้งหมดจาก {host} โปรดเรียกใช้คำสั่งสิ่งนี้หากต้องการยกเลิกอินสแตนซ์ เช่น ไม่มีอยู่แล้ว"
|
removeAllFollowingDescription: "การที่คุณดำเนินการนี้จะเลิกติดตามบัญชีทั้งหมดจาก {host}
|
||||||
|
โปรดเรียกใช้คำสั่งสิ่งนี้หากต้องการยกเลิกอินสแตนซ์ เช่น ไม่มีอยู่แล้ว"
|
||||||
userSuspended: "ผู้ใช้รายนี้ถูกระงับการใช้งาน"
|
userSuspended: "ผู้ใช้รายนี้ถูกระงับการใช้งาน"
|
||||||
userSilenced: "ผู้ใช้รายนี้กำลังถูกปิดกั้น"
|
userSilenced: "ผู้ใช้รายนี้กำลังถูกปิดกั้น"
|
||||||
yourAccountSuspendedTitle: "บัญชีนี้นั้นถูกระงับ"
|
yourAccountSuspendedTitle: "บัญชีนี้นั้นถูกระงับ"
|
||||||
yourAccountSuspendedDescription: "บัญชีนี้ถูกระงับ เนื่องจากละเมิดข้อกำหนดในการให้บริการของเซิร์ฟเวอร์หรืออาจจะละเมิดหลักเกณฑ์ชุมชน หรือ อาจจะโดนร้องเรียนเรื่องการละเมิดลิขสิทธิ์และอื่นๆอย่างต่อเนื่องซ้ำๆ หากคุณคิดว่าไม่ได้ทำผิดจริงๆหรือตัดสินผิดพลาด ได้โปรดกรุณาติดต่อผู้ดูแลระบบหากคุณต้องการทราบเหตุผลโดยละเอียดเพิ่มเติม และขอความกรุณาอย่าสร้างบัญชีใหม่"
|
yourAccountSuspendedDescription: "บัญชีนี้ถูกระงับ เนื่องจากละเมิดข้อกำหนดในการให้บริการของเซิร์ฟเวอร์หรืออาจจะละเมิดหลักเกณฑ์ชุมชน
|
||||||
|
หรือ อาจจะโดนร้องเรียนเรื่องการละเมิดลิขสิทธิ์และอื่นๆอย่างต่อเนื่องซ้ำๆ หากคุณคิดว่าไม่ได้ทำผิดจริงๆหรือตัดสินผิดพลาด
|
||||||
|
ได้โปรดกรุณาติดต่อผู้ดูแลระบบหากคุณต้องการทราบเหตุผลโดยละเอียดเพิ่มเติม และขอความกรุณาอย่าสร้างบัญชีใหม่"
|
||||||
menu: "เมนู"
|
menu: "เมนู"
|
||||||
divider: "ตัวแบ่ง"
|
divider: "ตัวแบ่ง"
|
||||||
addItem: "เพิ่มรายการ"
|
addItem: "เพิ่มรายการ"
|
||||||
|
@ -589,13 +616,15 @@ smtpHost: "โฮสต์"
|
||||||
smtpPort: "พอร์ต"
|
smtpPort: "พอร์ต"
|
||||||
smtpUser: "ชื่อผู้ใช้"
|
smtpUser: "ชื่อผู้ใช้"
|
||||||
smtpPass: "รหัสผ่าน"
|
smtpPass: "รหัสผ่าน"
|
||||||
emptyToDisableSmtpAuth: "ปล่อยชื่อผู้ใช้และรหัสผ่านว่างไว้เพื่อปิดใช้งานการยืนยัน SMTP"
|
emptyToDisableSmtpAuth: "ปล่อยชื่อผู้ใช้และรหัสผ่านว่างไว้เพื่อปิดใช้งานการยืนยัน
|
||||||
|
SMTP"
|
||||||
smtpSecure: "ใช้โดยนัย SSL/TLS สำหรับการเชื่อมต่อ SMTP"
|
smtpSecure: "ใช้โดยนัย SSL/TLS สำหรับการเชื่อมต่อ SMTP"
|
||||||
smtpSecureInfo: "ปิดสิ่งนี้เมื่อใช้ STARTTLS"
|
smtpSecureInfo: "ปิดสิ่งนี้เมื่อใช้ STARTTLS"
|
||||||
testEmail: "ทดสอบการส่งอีเมล"
|
testEmail: "ทดสอบการส่งอีเมล"
|
||||||
wordMute: "ปิดเสียงคำ"
|
wordMute: "ปิดเสียงคำ"
|
||||||
regexpError: "ข้อผิดพลาดของนิพจน์ทั่วไป"
|
regexpError: "ข้อผิดพลาดของนิพจน์ทั่วไป"
|
||||||
regexpErrorDescription: "เกิดข้อผิดพลาดในนิพจน์ทั่วไปในบรรทัดที่ {line} ของการปิดเสียงคำ {tab} ของคุณ:"
|
regexpErrorDescription: "เกิดข้อผิดพลาดในนิพจน์ทั่วไปในบรรทัดที่ {line} ของการปิดเสียงคำ
|
||||||
|
{tab} ของคุณ:"
|
||||||
instanceMute: "ปิดเสียง อินสแตนซ์"
|
instanceMute: "ปิดเสียง อินสแตนซ์"
|
||||||
userSaysSomething: "{name} พูดอะไรบางอย่าง"
|
userSaysSomething: "{name} พูดอะไรบางอย่าง"
|
||||||
makeActive: "เปิดใช้งาน"
|
makeActive: "เปิดใช้งาน"
|
||||||
|
@ -611,10 +640,12 @@ create: "สร้าง"
|
||||||
notificationSetting: "ตั้งค่าการแจ้งเตือน"
|
notificationSetting: "ตั้งค่าการแจ้งเตือน"
|
||||||
notificationSettingDesc: "เลือกประเภทการแจ้งเตือนที่ต้องการจะแสดง"
|
notificationSettingDesc: "เลือกประเภทการแจ้งเตือนที่ต้องการจะแสดง"
|
||||||
useGlobalSetting: "ใช้การตั้งค่าส่วนกลาง"
|
useGlobalSetting: "ใช้การตั้งค่าส่วนกลาง"
|
||||||
useGlobalSettingDesc: "หากเปิดไว้ ระบบจะใช้การตั้งค่าการแจ้งเตือนของบัญชีของคุณ หากปิดอยู่ สามารถทำการกำหนดค่าแต่ละรายการได้นะ"
|
useGlobalSettingDesc: "หากเปิดไว้ ระบบจะใช้การตั้งค่าการแจ้งเตือนของบัญชีของคุณ หากปิดอยู่
|
||||||
|
สามารถทำการกำหนดค่าแต่ละรายการได้นะ"
|
||||||
other: "อื่น ๆ"
|
other: "อื่น ๆ"
|
||||||
regenerateLoginToken: "สร้างโทเค็นการเข้าสู่ระบบอีกครั้ง"
|
regenerateLoginToken: "สร้างโทเค็นการเข้าสู่ระบบอีกครั้ง"
|
||||||
regenerateLoginTokenDescription: "สร้างโทเค็นใหม่ที่ใช้ภายในระหว่างการเข้าสู่ระบบ โดยตามหลักปกติแล้วการดำเนินการนี้ไม่จำเป็น หากสร้างใหม่ อุปกรณ์ทั้งหมดจะถูกออกจากระบบนะ"
|
regenerateLoginTokenDescription: "สร้างโทเค็นใหม่ที่ใช้ภายในระหว่างการเข้าสู่ระบบ
|
||||||
|
โดยตามหลักปกติแล้วการดำเนินการนี้ไม่จำเป็น หากสร้างใหม่ อุปกรณ์ทั้งหมดจะถูกออกจากระบบนะ"
|
||||||
setMultipleBySeparatingWithSpace: "คั่นหลายรายการด้วยช่องว่าง"
|
setMultipleBySeparatingWithSpace: "คั่นหลายรายการด้วยช่องว่าง"
|
||||||
fileIdOrUrl: "ไฟล์ ID หรือ URL"
|
fileIdOrUrl: "ไฟล์ ID หรือ URL"
|
||||||
behavior: "พฤติกรรม"
|
behavior: "พฤติกรรม"
|
||||||
|
@ -622,7 +653,8 @@ sample: "ตัวอย่าง"
|
||||||
abuseReports: "รายงาน"
|
abuseReports: "รายงาน"
|
||||||
reportAbuse: "รายงาน"
|
reportAbuse: "รายงาน"
|
||||||
reportAbuseOf: "รายงาน {ชื่อ}"
|
reportAbuseOf: "รายงาน {ชื่อ}"
|
||||||
fillAbuseReportDescription: "กรุณากรอกรายละเอียดเกี่ยวกับรายงานนี้ หากเป็นเรื่องเกี่ยวกับโน้ตโดยเฉพาะ ได้โปรดระบุ URL"
|
fillAbuseReportDescription: "กรุณากรอกรายละเอียดเกี่ยวกับรายงานนี้ หากเป็นเรื่องเกี่ยวกับโน้ตโดยเฉพาะ
|
||||||
|
ได้โปรดระบุ URL"
|
||||||
abuseReported: "เราได้ส่งรายงานของคุณไปแล้ว ขอบคุณมากๆนะ"
|
abuseReported: "เราได้ส่งรายงานของคุณไปแล้ว ขอบคุณมากๆนะ"
|
||||||
reporter: "นักข่าว"
|
reporter: "นักข่าว"
|
||||||
reporteeOrigin: "รายงานต้นทาง"
|
reporteeOrigin: "รายงานต้นทาง"
|
||||||
|
@ -648,7 +680,8 @@ createNewClip: "สร้างคลิปใหม่"
|
||||||
unclip: "ลบคลิป"
|
unclip: "ลบคลิป"
|
||||||
confirmToUnclipAlreadyClippedNote: "โน้ตนี้เป็นส่วนหนึ่งของคลิป \"{name}\" แล้ว คุณต้องการลบออกจากคลิปนี้แทนอย่างงั้นหรอ?"
|
confirmToUnclipAlreadyClippedNote: "โน้ตนี้เป็นส่วนหนึ่งของคลิป \"{name}\" แล้ว คุณต้องการลบออกจากคลิปนี้แทนอย่างงั้นหรอ?"
|
||||||
public: "สาธารณะ"
|
public: "สาธารณะ"
|
||||||
i18nInfo: "Firefish กำลังได้รับการแปลเป็นภาษาต่างๆ โดยอาสาสมัคร คุณสามารถช่วยเหลือได้ที่ {link}"
|
i18nInfo: "Firefish กำลังได้รับการแปลเป็นภาษาต่างๆ โดยอาสาสมัคร คุณสามารถช่วยเหลือได้ที่
|
||||||
|
{link}"
|
||||||
manageAccessTokens: "การจัดการโทเค็นการเข้าถึง"
|
manageAccessTokens: "การจัดการโทเค็นการเข้าถึง"
|
||||||
accountInfo: "ข้อมูลบัญชี"
|
accountInfo: "ข้อมูลบัญชี"
|
||||||
notesCount: "จำนวนของโน้ต"
|
notesCount: "จำนวนของโน้ต"
|
||||||
|
@ -667,8 +700,10 @@ no: "ไม่"
|
||||||
driveFilesCount: "จำนวนไฟล์ไดรฟ์"
|
driveFilesCount: "จำนวนไฟล์ไดรฟ์"
|
||||||
driveUsage: "การใช้พื้นที่ไดรฟ์"
|
driveUsage: "การใช้พื้นที่ไดรฟ์"
|
||||||
noCrawle: "ปฏิเสธการจัดทำดัชนีของโปรแกรมรวบรวมข้อมูล"
|
noCrawle: "ปฏิเสธการจัดทำดัชนีของโปรแกรมรวบรวมข้อมูล"
|
||||||
noCrawleDescription: "ขอให้เครื่องมือค้นหาไม่จัดทำดัชนีหน้าโปรไฟล์ บันทึกย่อ หน้า ฯลฯ"
|
noCrawleDescription: "ขอให้เครื่องมือค้นหาไม่จัดทำดัชนีหน้าโปรไฟล์ บันทึกย่อ หน้า
|
||||||
lockedAccountInfo: "เว้นแต่ว่าคุณจะต้องตั้งค่าการเปิดเผยโน้ตเป็น \"ผู้ติดตามเท่านั้น\" โน้ตย่อของคุณจะปรากฏแก่ทุกคน ถึงแม้ว่าคุณจะเป็นกำหนดให้ผู้ติดตามต้องได้รับการอนุมัติด้วยตนเองก็ตาม"
|
ฯลฯ"
|
||||||
|
lockedAccountInfo: "เว้นแต่ว่าคุณจะต้องตั้งค่าการเปิดเผยโน้ตเป็น \"ผู้ติดตามเท่านั้น\"\
|
||||||
|
\ โน้ตย่อของคุณจะปรากฏแก่ทุกคน ถึงแม้ว่าคุณจะเป็นกำหนดให้ผู้ติดตามต้องได้รับการอนุมัติด้วยตนเองก็ตาม"
|
||||||
alwaysMarkSensitive: "ทำเครื่องหมายเป็น NSFW เป็นค่าเริ่มต้น"
|
alwaysMarkSensitive: "ทำเครื่องหมายเป็น NSFW เป็นค่าเริ่มต้น"
|
||||||
loadRawImages: "โหลดภาพต้นฉบับแทนการแสดงภาพขนาดย่อ"
|
loadRawImages: "โหลดภาพต้นฉบับแทนการแสดงภาพขนาดย่อ"
|
||||||
disableShowingAnimatedImages: "ไม่ต้องเล่นภาพเคลื่อนไหว"
|
disableShowingAnimatedImages: "ไม่ต้องเล่นภาพเคลื่อนไหว"
|
||||||
|
@ -684,7 +719,8 @@ clips: "คลิป"
|
||||||
experimentalFeatures: "ฟังก์ชั่นทดสอบ"
|
experimentalFeatures: "ฟังก์ชั่นทดสอบ"
|
||||||
developer: "สำหรับนักพัฒนา"
|
developer: "สำหรับนักพัฒนา"
|
||||||
makeExplorable: "ทำให้บัญชีมองเห็นใน \"สำรวจ\""
|
makeExplorable: "ทำให้บัญชีมองเห็นใน \"สำรวจ\""
|
||||||
makeExplorableDescription: "ถ้าหากคุณปิดการทำงานนี้ บัญชีของคุณนั้นจะไม่แสดงในส่วน \"สำรวจ\" นะ"
|
makeExplorableDescription: "ถ้าหากคุณปิดการทำงานนี้ บัญชีของคุณนั้นจะไม่แสดงในส่วน
|
||||||
|
\"สำรวจ\" นะ"
|
||||||
showGapBetweenNotesInTimeline: "แสดงช่องว่างระหว่างโพสต์บนไทม์ไลน์"
|
showGapBetweenNotesInTimeline: "แสดงช่องว่างระหว่างโพสต์บนไทม์ไลน์"
|
||||||
duplicate: "ทำซ้ำ"
|
duplicate: "ทำซ้ำ"
|
||||||
left: "ซ้าย"
|
left: "ซ้าย"
|
||||||
|
@ -699,7 +735,9 @@ onlineUsersCount: "{n} ผู้ใช้คนนี้กำลังออน
|
||||||
nUsers: "{n} ผู้ใช้งาน"
|
nUsers: "{n} ผู้ใช้งาน"
|
||||||
nNotes: "{n} โน้ต"
|
nNotes: "{n} โน้ต"
|
||||||
sendErrorReports: "ส่งรายงานว่าข้อผิดพลาด"
|
sendErrorReports: "ส่งรายงานว่าข้อผิดพลาด"
|
||||||
sendErrorReportsDescription: "เมื่อเปิดใช้งาน ข้อมูลข้อผิดพลาดโดยรายละเอียดนั้นจะถูกแชร์ให้กับ Firefish เมื่อเกิดปัญหา ซึ่งช่วยปรับปรุงคุณภาพของ Firefish\nซึ่งจะรวมถึงข้อมูล เช่น เวอร์ชั่นของระบบปฏิบัติการ เบราว์เซอร์ที่คุณใช้ กิจกรรมของคุณใน Firefish เป็นต้น"
|
sendErrorReportsDescription: "เมื่อเปิดใช้งาน ข้อมูลข้อผิดพลาดโดยรายละเอียดนั้นจะถูกแชร์ให้กับ
|
||||||
|
Firefish เมื่อเกิดปัญหา ซึ่งช่วยปรับปรุงคุณภาพของ Firefish\nซึ่งจะรวมถึงข้อมูล เช่น
|
||||||
|
เวอร์ชั่นของระบบปฏิบัติการ เบราว์เซอร์ที่คุณใช้ กิจกรรมของคุณใน Firefish เป็นต้น"
|
||||||
myTheme: "ธีมของฉัน"
|
myTheme: "ธีมของฉัน"
|
||||||
backgroundColor: "ภาพพื้นหลัง"
|
backgroundColor: "ภาพพื้นหลัง"
|
||||||
accentColor: "รูปแบบสี"
|
accentColor: "รูปแบบสี"
|
||||||
|
@ -745,7 +783,8 @@ userInfo: "ข้อมูลผู้ใช้"
|
||||||
unknown: "ไม่ทราบสถานะ"
|
unknown: "ไม่ทราบสถานะ"
|
||||||
onlineStatus: "สถานะออนไลน์"
|
onlineStatus: "สถานะออนไลน์"
|
||||||
hideOnlineStatus: "ซ่อนสถานะออนไลน์"
|
hideOnlineStatus: "ซ่อนสถานะออนไลน์"
|
||||||
hideOnlineStatusDescription: "การซ่อนสถานะออนไลน์ของคุณช่วยลดความสะดวกของคุณสมบัติบางอย่าง เช่น การค้นหา อ่ะนะ"
|
hideOnlineStatusDescription: "การซ่อนสถานะออนไลน์ของคุณช่วยลดความสะดวกของคุณสมบัติบางอย่าง
|
||||||
|
เช่น การค้นหา อ่ะนะ"
|
||||||
online: "ออนไลน์"
|
online: "ออนไลน์"
|
||||||
active: "ใช้งานอยู่"
|
active: "ใช้งานอยู่"
|
||||||
offline: "ออฟไลน์"
|
offline: "ออฟไลน์"
|
||||||
|
@ -795,7 +834,8 @@ whatIsNew: "แสดงการเปลี่ยนแปลง"
|
||||||
translate: "แปลภาษา"
|
translate: "แปลภาษา"
|
||||||
translatedFrom: "แปลมาจาก {x}"
|
translatedFrom: "แปลมาจาก {x}"
|
||||||
accountDeletionInProgress: "กำลังดำเนินการลบบัญชีอยู่"
|
accountDeletionInProgress: "กำลังดำเนินการลบบัญชีอยู่"
|
||||||
usernameInfo: "ชื่อที่ระบุบัญชีของคุณจากผู้อื่นในเซิร์ฟเวอร์นี้ คุณสามารถใช้ตัวอักษร (a~z, A~Z), ตัวเลข (0~9) หรือขีดล่าง (_) ชื่อผู้ใช้ไม่สามารถเปลี่ยนแปลงได้ในภายหลัง"
|
usernameInfo: "ชื่อที่ระบุบัญชีของคุณจากผู้อื่นในเซิร์ฟเวอร์นี้ คุณสามารถใช้ตัวอักษร
|
||||||
|
(a~z, A~Z), ตัวเลข (0~9) หรือขีดล่าง (_) ชื่อผู้ใช้ไม่สามารถเปลี่ยนแปลงได้ในภายหลัง"
|
||||||
aiChanMode: "โหมด Ai "
|
aiChanMode: "โหมด Ai "
|
||||||
keepCw: "เก็บคำเตือนเนื้อหา"
|
keepCw: "เก็บคำเตือนเนื้อหา"
|
||||||
pubSub: "บัญชีผับ/ย่อย"
|
pubSub: "บัญชีผับ/ย่อย"
|
||||||
|
@ -864,7 +904,8 @@ typeToConfirm: "โปรดป้อน {x} เพื่อยืนยัน"
|
||||||
deleteAccount: "ลบบัญชี"
|
deleteAccount: "ลบบัญชี"
|
||||||
document: "เอกสาร"
|
document: "เอกสาร"
|
||||||
numberOfPageCache: "จำนวนหน้าเพจที่แคช"
|
numberOfPageCache: "จำนวนหน้าเพจที่แคช"
|
||||||
numberOfPageCacheDescription: "การเพิ่มจำนวนนี้จะช่วยเพิ่มความสะดวกให้กับผู้ใช้งาน แต่จะทำให้เซิร์ฟเวอร์โหลดมากขึ้นและต้องใช้หน่วยความจำมากขึ้นอีกด้วย"
|
numberOfPageCacheDescription: "การเพิ่มจำนวนนี้จะช่วยเพิ่มความสะดวกให้กับผู้ใช้งาน
|
||||||
|
แต่จะทำให้เซิร์ฟเวอร์โหลดมากขึ้นและต้องใช้หน่วยความจำมากขึ้นอีกด้วย"
|
||||||
logoutConfirm: "คุณแน่ใจว่าต้องการออกจากระบบ?"
|
logoutConfirm: "คุณแน่ใจว่าต้องการออกจากระบบ?"
|
||||||
lastActiveDate: "ใช้งานล่าสุดที่"
|
lastActiveDate: "ใช้งานล่าสุดที่"
|
||||||
statusbar: "ไอคอนบนแถบสถานะ"
|
statusbar: "ไอคอนบนแถบสถานะ"
|
||||||
|
@ -881,22 +922,29 @@ sensitiveMediaDetection: "การตรวจจับของสื่อ NS
|
||||||
localOnly: "เฉพาะท้องถิ่น"
|
localOnly: "เฉพาะท้องถิ่น"
|
||||||
remoteOnly: "รีโมทเท่านั้น"
|
remoteOnly: "รีโมทเท่านั้น"
|
||||||
failedToUpload: "การอัปโหลดล้มเหลว"
|
failedToUpload: "การอัปโหลดล้มเหลว"
|
||||||
cannotUploadBecauseInappropriate: "ไม่สามารถอัปโหลดไฟล์นี้ได้เนื่องจากระบบตรวจพบบางส่วนของไฟล์ว่านี้อาจจะเป็น NSFW"
|
cannotUploadBecauseInappropriate: "ไม่สามารถอัปโหลดไฟล์นี้ได้เนื่องจากระบบตรวจพบบางส่วนของไฟล์ว่านี้อาจจะเป็น
|
||||||
|
NSFW"
|
||||||
cannotUploadBecauseNoFreeSpace: "การอัปโหลดนั้นล้มเหลวเนื่องจากไม่มีความจุของไดรฟ์"
|
cannotUploadBecauseNoFreeSpace: "การอัปโหลดนั้นล้มเหลวเนื่องจากไม่มีความจุของไดรฟ์"
|
||||||
beta: "เบต้า"
|
beta: "เบต้า"
|
||||||
enableAutoSensitive: "ทำเครื่องหมาย NSFW อัตโนมัติ"
|
enableAutoSensitive: "ทำเครื่องหมาย NSFW อัตโนมัติ"
|
||||||
enableAutoSensitiveDescription: "อนุญาตให้ตรวจหาและทำเครื่องหมายสื่อ NSFW โดยอัตโนมัติผ่านการเรียนรู้ของเครื่องหากเป็นไปได้ แม้ว่าตัวเลือกนี้จะถูกปิดใช้งาน แต่ก็สามารถเปิดใช้งานได้ทั้งอินสแตนซ์นี้"
|
enableAutoSensitiveDescription: "อนุญาตให้ตรวจหาและทำเครื่องหมายสื่อ NSFW โดยอัตโนมัติผ่านการเรียนรู้ของเครื่องหากเป็นไปได้
|
||||||
activeEmailValidationDescription: "เปิดใช้งานการตรวจสอบที่อยู่อีเมลให้มีความเข้มงวดยิ่งขึ้น ซึ่งอาจจะรวมไปถึงการตรวจสอบที่อยู่อีเมล์ที่ใช้แล้วทิ้งและโดยให้พิจารณาว่าสามารถสื่อสารด้วยได้หรือไม่ เมื่อไม่เลือกระบบจะตรวจสอบเฉพาะรูปแบบของอีเมลเท่านั้น"
|
แม้ว่าตัวเลือกนี้จะถูกปิดใช้งาน แต่ก็สามารถเปิดใช้งานได้ทั้งอินสแตนซ์นี้"
|
||||||
|
activeEmailValidationDescription: "เปิดใช้งานการตรวจสอบที่อยู่อีเมลให้มีความเข้มงวดยิ่งขึ้น
|
||||||
|
ซึ่งอาจจะรวมไปถึงการตรวจสอบที่อยู่อีเมล์ที่ใช้แล้วทิ้งและโดยให้พิจารณาว่าสามารถสื่อสารด้วยได้หรือไม่
|
||||||
|
เมื่อไม่เลือกระบบจะตรวจสอบเฉพาะรูปแบบของอีเมลเท่านั้น"
|
||||||
navbar: "แถบนำทาง"
|
navbar: "แถบนำทาง"
|
||||||
shuffle: "สลับ"
|
shuffle: "สลับ"
|
||||||
account: "บัญชีผู้ใช้"
|
account: "บัญชีผู้ใช้"
|
||||||
move: "ย้าย"
|
move: "ย้าย"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "ลดความพยายามในการดูแลเซิร์ฟเวอร์ผ่านการจดจำสื่อ NSFW โดยอัตโนมัติผ่านการเรียนรู้ของเครื่อง การทำสิ่งนี้อาจจะเพิ่มภาระบนเซิร์ฟเวอร์เล็กน้อย"
|
description: "ลดความพยายามในการดูแลเซิร์ฟเวอร์ผ่านการจดจำสื่อ NSFW โดยอัตโนมัติผ่านการเรียนรู้ของเครื่อง
|
||||||
|
การทำสิ่งนี้อาจจะเพิ่มภาระบนเซิร์ฟเวอร์เล็กน้อย"
|
||||||
sensitivity: "การตรวจจับความไว"
|
sensitivity: "การตรวจจับความไว"
|
||||||
sensitivityDescription: "การลดความไวนั้นจะนำไปสู่การตรวจจับที่ผิดพลาดน้อยลง (ผลบวกที่ผิดพลาด) แต่ในขณะที่การเพิ่มนั้นจะนำไปสู่การตรวจหาที่พลาดน้อยลง (ผลลบเท็จ)"
|
sensitivityDescription: "การลดความไวนั้นจะนำไปสู่การตรวจจับที่ผิดพลาดน้อยลง (ผลบวกที่ผิดพลาด)
|
||||||
|
แต่ในขณะที่การเพิ่มนั้นจะนำไปสู่การตรวจหาที่พลาดน้อยลง (ผลลบเท็จ)"
|
||||||
setSensitiveFlagAutomatically: "ทำเครื่องหมายว่าเป็น NSFW"
|
setSensitiveFlagAutomatically: "ทำเครื่องหมายว่าเป็น NSFW"
|
||||||
setSensitiveFlagAutomaticallyDescription: "ผลลัพธ์ของการตรวจจับภายในนั้นจะยังคงอยู่ ถึงแม้ว่าจะปิดตัวเลือกนี้"
|
setSensitiveFlagAutomaticallyDescription: "ผลลัพธ์ของการตรวจจับภายในนั้นจะยังคงอยู่
|
||||||
|
ถึงแม้ว่าจะปิดตัวเลือกนี้"
|
||||||
analyzeVideos: "เปิดใช้งานวิเคราะห์ของวิดีโอ"
|
analyzeVideos: "เปิดใช้งานวิเคราะห์ของวิดีโอ"
|
||||||
analyzeVideosDescription: "การวิเคราะห์วิดีโอนอกเหนือจากรูปภาพนั้น การทำสิ่งนี้จะทำให้เพิ่มภาระบนเซิร์ฟเวอร์เล็กน้อย"
|
analyzeVideosDescription: "การวิเคราะห์วิดีโอนอกเหนือจากรูปภาพนั้น การทำสิ่งนี้จะทำให้เพิ่มภาระบนเซิร์ฟเวอร์เล็กน้อย"
|
||||||
_emailUnavailable:
|
_emailUnavailable:
|
||||||
|
@ -915,7 +963,8 @@ _signup:
|
||||||
emailSent: "เราได้ส่งอีเมลยืนยันไปยังที่อยู่อีเมลของคุณแล้วนะ ({email}) โปรดคลิกลิงก์ที่รวมไว้เพื่อสร้างบัญชีให้เสร็จสิ้น"
|
emailSent: "เราได้ส่งอีเมลยืนยันไปยังที่อยู่อีเมลของคุณแล้วนะ ({email}) โปรดคลิกลิงก์ที่รวมไว้เพื่อสร้างบัญชีให้เสร็จสิ้น"
|
||||||
_accountDelete:
|
_accountDelete:
|
||||||
accountDelete: "ลบบัญชีผู้ใช้"
|
accountDelete: "ลบบัญชีผู้ใช้"
|
||||||
mayTakeTime: "เนื่องจากการลบบัญชีนี้จะเป็นกระบวนการที่ต้องใช้ทรัพยากรมาก จึงอาจจะต้องใช้เวลาสักครู่ถึงจะเสร็จสมบูรณ์ ทั้งนี้ขึ้นอยู่กับจำนวนเนื้อหาที่คุณสร้างและจำนวนไฟล์ที่คุณอัปโหลดนะ"
|
mayTakeTime: "เนื่องจากการลบบัญชีนี้จะเป็นกระบวนการที่ต้องใช้ทรัพยากรมาก จึงอาจจะต้องใช้เวลาสักครู่ถึงจะเสร็จสมบูรณ์
|
||||||
|
ทั้งนี้ขึ้นอยู่กับจำนวนเนื้อหาที่คุณสร้างและจำนวนไฟล์ที่คุณอัปโหลดนะ"
|
||||||
sendEmail: "เมื่อการลบบัญชีนี้เสร็จสิ้น เราอาจจะส่งอีเมลไปยังที่อยู่อีเมลของคุณที่เคยลงทะเบียนไว้กับบัญชีนี้นะ"
|
sendEmail: "เมื่อการลบบัญชีนี้เสร็จสิ้น เราอาจจะส่งอีเมลไปยังที่อยู่อีเมลของคุณที่เคยลงทะเบียนไว้กับบัญชีนี้นะ"
|
||||||
requestAccountDelete: "ร้องขอให้ลบบัญชี"
|
requestAccountDelete: "ร้องขอให้ลบบัญชี"
|
||||||
started: "การลบได้เริ่มต้นขึ้น"
|
started: "การลบได้เริ่มต้นขึ้น"
|
||||||
|
@ -950,11 +999,13 @@ _preferencesBackups:
|
||||||
inputName: "กรุณาป้อนชื่อสำหรับข้อมูลสำรองนี้"
|
inputName: "กรุณาป้อนชื่อสำหรับข้อมูลสำรองนี้"
|
||||||
cannotSave: "การบันทึกล้มเหลว"
|
cannotSave: "การบันทึกล้มเหลว"
|
||||||
nameAlreadyExists: "มีข้อมูลสำรองชื่อ \"{name}\" นี้อยู่แล้ว กรุณาป้อนชื่ออื่นนะ"
|
nameAlreadyExists: "มีข้อมูลสำรองชื่อ \"{name}\" นี้อยู่แล้ว กรุณาป้อนชื่ออื่นนะ"
|
||||||
applyConfirm: "คุณต้องการใช้ข้อมูลสำรอง \"{name}\" กับอุปกรณ์นี้อย่างงั้นจริงหรอ การตั้งค่าที่มีอยู่ของอุปกรณ์นี้จะถูกเขียนทับนะ"
|
applyConfirm: "คุณต้องการใช้ข้อมูลสำรอง \"{name}\" กับอุปกรณ์นี้อย่างงั้นจริงหรอ
|
||||||
|
การตั้งค่าที่มีอยู่ของอุปกรณ์นี้จะถูกเขียนทับนะ"
|
||||||
saveConfirm: "บันทึกข้อมูลสำรองเป็น {name} มั้ย?"
|
saveConfirm: "บันทึกข้อมูลสำรองเป็น {name} มั้ย?"
|
||||||
deleteConfirm: "ลบข้อมูลสำรอง {name} มั้ย?"
|
deleteConfirm: "ลบข้อมูลสำรอง {name} มั้ย?"
|
||||||
renameConfirm: "เปลี่ยนชื่อข้อมูลสำรองนี้จาก \"{old}\" เป็น \"{new}\" หรือป่าว"
|
renameConfirm: "เปลี่ยนชื่อข้อมูลสำรองนี้จาก \"{old}\" เป็น \"{new}\" หรือป่าว"
|
||||||
noBackups: "ไม่มีข้อมูลสำรองนะ คุณสามารถสำรองข้อมูลการตั้งค่าไคลเอนต์ของคุณบนเซิร์ฟเวอร์นี้โดยใช้ \"สร้างการสำรองข้อมูลใหม่\"ได้นะ"
|
noBackups: "ไม่มีข้อมูลสำรองนะ คุณสามารถสำรองข้อมูลการตั้งค่าไคลเอนต์ของคุณบนเซิร์ฟเวอร์นี้โดยใช้
|
||||||
|
\"สร้างการสำรองข้อมูลใหม่\"ได้นะ"
|
||||||
createdAt: "สร้างเมื่อ: {date} {time}"
|
createdAt: "สร้างเมื่อ: {date} {time}"
|
||||||
updatedAt: "อัปเดตเมื่อ: {date} {time}"
|
updatedAt: "อัปเดตเมื่อ: {date} {time}"
|
||||||
cannotLoad: "การโหลดล้มเหลว"
|
cannotLoad: "การโหลดล้มเหลว"
|
||||||
|
@ -972,7 +1023,8 @@ _aboutFirefish:
|
||||||
source: "ซอร์สโค้ด"
|
source: "ซอร์สโค้ด"
|
||||||
translation: "รับแปลภาษา Firefish"
|
translation: "รับแปลภาษา Firefish"
|
||||||
donate: "บริจาคให้กับ Firefish"
|
donate: "บริจาคให้กับ Firefish"
|
||||||
morePatrons: "เราขอขอบคุณสำหรับความช่วยเหลือจากผู้ช่วยอื่นๆ ที่ไม่ได้ระบุไว้ที่นี่นะ ขอขอบคุณ! 🥰"
|
morePatrons: "เราขอขอบคุณสำหรับความช่วยเหลือจากผู้ช่วยอื่นๆ ที่ไม่ได้ระบุไว้ที่นี่นะ
|
||||||
|
ขอขอบคุณ! 🥰"
|
||||||
patrons: "สมาชิกพันธมิตร"
|
patrons: "สมาชิกพันธมิตร"
|
||||||
_nsfw:
|
_nsfw:
|
||||||
respect: "ซ่อนสื่อ NSFW"
|
respect: "ซ่อนสื่อ NSFW"
|
||||||
|
@ -980,7 +1032,8 @@ _nsfw:
|
||||||
force: "ซ่อนสื่อทั้งหมด"
|
force: "ซ่อนสื่อทั้งหมด"
|
||||||
_mfm:
|
_mfm:
|
||||||
cheatSheet: "โค้ด MFM Cheat Sheet"
|
cheatSheet: "โค้ด MFM Cheat Sheet"
|
||||||
intro: "MFM เป็นภาษามาร์กอัปพิเศษเฉพาะของ Firefish ที่สามารถใช้ได้ในหลายที่ คุณยังสามารถดูรายการไวยากรณ์ MFM ที่มีอยู่ทั้งหมดได้ที่นี่นะ"
|
intro: "MFM เป็นภาษามาร์กอัปพิเศษเฉพาะของ Firefish ที่สามารถใช้ได้ในหลายที่ คุณยังสามารถดูรายการไวยากรณ์
|
||||||
|
MFM ที่มีอยู่ทั้งหมดได้ที่นี่นะ"
|
||||||
dummy: "Firefish ขยายโลกของ Fediverse"
|
dummy: "Firefish ขยายโลกของ Fediverse"
|
||||||
mention: "กล่าวถึง"
|
mention: "กล่าวถึง"
|
||||||
mentionDescription: "คุณสามารถระบุผู้ใช้โดยใช้ At-Symbol และชื่อผู้ใช้ได้นะ"
|
mentionDescription: "คุณสามารถระบุผู้ใช้โดยใช้ At-Symbol และชื่อผู้ใช้ได้นะ"
|
||||||
|
@ -1069,15 +1122,18 @@ _menuDisplay:
|
||||||
hide: "ซ่อน"
|
hide: "ซ่อน"
|
||||||
_wordMute:
|
_wordMute:
|
||||||
muteWords: "ปิดเสียงคำ"
|
muteWords: "ปิดเสียงคำ"
|
||||||
muteWordsDescription: "คั่นด้วยช่องว่างสำหรับเงื่อนไข AND หรือด้วยการขึ้นบรรทัดใหม่สำหรับเงื่อนไข OR นะ"
|
muteWordsDescription: "คั่นด้วยช่องว่างสำหรับเงื่อนไข AND หรือด้วยการขึ้นบรรทัดใหม่สำหรับเงื่อนไข
|
||||||
|
OR นะ"
|
||||||
muteWordsDescription2: "ล้อมรอบคีย์เวิร์ดด้วยเครื่องหมายทับเพื่อใช้นิพจน์ทั่วไป"
|
muteWordsDescription2: "ล้อมรอบคีย์เวิร์ดด้วยเครื่องหมายทับเพื่อใช้นิพจน์ทั่วไป"
|
||||||
softDescription: "ซ่อนโน้ตให้ตรงตามเงื่อนไขที่ตั้งไว้จากไทม์ไลน์"
|
softDescription: "ซ่อนโน้ตให้ตรงตามเงื่อนไขที่ตั้งไว้จากไทม์ไลน์"
|
||||||
hardDescription: "ป้องกันไม่ให้โน้ตย่อที่ตรงตามเงื่อนไขที่ตั้งไว้ไม่ให้ถูกเพิ่มลงในไทม์ไลน์ นอกจากนี้ โน้ตเหล่านี้จะไม่ถูกเพิ่มลงในไทม์ไลน์แม้ว่าจะมีการเปลี่ยนแปลงเงื่อนไขยังไงก็ตาม"
|
hardDescription: "ป้องกันไม่ให้โน้ตย่อที่ตรงตามเงื่อนไขที่ตั้งไว้ไม่ให้ถูกเพิ่มลงในไทม์ไลน์
|
||||||
|
นอกจากนี้ โน้ตเหล่านี้จะไม่ถูกเพิ่มลงในไทม์ไลน์แม้ว่าจะมีการเปลี่ยนแปลงเงื่อนไขยังไงก็ตาม"
|
||||||
soft: "ซอฟ"
|
soft: "ซอฟ"
|
||||||
hard: "ยาก"
|
hard: "ยาก"
|
||||||
mutedNotes: "ปิดเสียงโน้ต"
|
mutedNotes: "ปิดเสียงโน้ต"
|
||||||
_instanceMute:
|
_instanceMute:
|
||||||
instanceMuteDescription: "การดำเนินการนี้จะปิดเสียง\"โน้ต/รีโน้ต\"จากอินสแตนซ์ที่อยู่ในรายการ รวมถึงบันทึกของผู้ใช้ที่ตอบกลับผู้ใช้จากอินสแตนซ์ที่ปิดเสียง"
|
instanceMuteDescription: "การดำเนินการนี้จะปิดเสียง\"โน้ต/รีโน้ต\"จากอินสแตนซ์ที่อยู่ในรายการ
|
||||||
|
รวมถึงบันทึกของผู้ใช้ที่ตอบกลับผู้ใช้จากอินสแตนซ์ที่ปิดเสียง"
|
||||||
instanceMuteDescription2: "คั่นด้วยการขึ้นบรรทัดใหม่"
|
instanceMuteDescription2: "คั่นด้วยการขึ้นบรรทัดใหม่"
|
||||||
title: "ซ่อนโน้ตจากอินสแตนซ์ที่มีอยู่ในรายการ"
|
title: "ซ่อนโน้ตจากอินสแตนซ์ที่มีอยู่ในรายการ"
|
||||||
heading: "รายชื่ออินสแตนซ์ที่ถูกปิดเสียง"
|
heading: "รายชื่ออินสแตนซ์ที่ถูกปิดเสียง"
|
||||||
|
@ -1191,3 +1247,23 @@ _deck:
|
||||||
antenna: "เสาอากาศ"
|
antenna: "เสาอากาศ"
|
||||||
list: "รายการ"
|
list: "รายการ"
|
||||||
mentions: "พูดถึง"
|
mentions: "พูดถึง"
|
||||||
|
noThankYou: ไม่ล่ะขอบคุณ
|
||||||
|
removeReaction: ลบรีเเอดชั่นของคุณ
|
||||||
|
renoteMute: ปิดเสียงบูส
|
||||||
|
renoteUnmute: เลิกปิดเสียงบูส
|
||||||
|
manageGroups: จัดการกลุ่ม
|
||||||
|
addInstance: เพิ่มเซิฟเวอร์
|
||||||
|
searchPlaceholder: ค้นหา Firefish
|
||||||
|
deleted: ลบแล้ว
|
||||||
|
editNote: แก้ไขโพสต์
|
||||||
|
edited: แก้ไขแล้วเมื่อ {date} {time}
|
||||||
|
jumpToPrevious: ข้ามไปที่ก่อนหน้านี้
|
||||||
|
listsDesc: ลิสต์รายการนั้นช่วยให้คุณได้สร้างไทม์ไลน์กับผู้ใช้ที่ระบุได้นะ ยังสามารถเข้าถึงได้จากหน้าไทม์ไลน์ได้อีกด้วย
|
||||||
|
enableEmojiReactions: เปิดใช้งานรีแอดชั่นอีโมจิ
|
||||||
|
selectChannel: เลือกช่อง
|
||||||
|
older: เก่ากว่านี้
|
||||||
|
newer: ใหม่กว่านี้
|
||||||
|
selectInstance: เลือกเซิฟเวอร์
|
||||||
|
showEmojisInReactionNotifications: แสดงอิโมจิในการแจ้งเตือนรีแอคชั่น
|
||||||
|
flagSpeakAsCat: พูดเหมือนแมว
|
||||||
|
cw: คำเตือนเนื้อหา
|
||||||
|
|
23
package.json
|
@ -1,16 +1,16 @@
|
||||||
{
|
{
|
||||||
"name": "firefish",
|
"name": "firefish",
|
||||||
"version": "1.0.5-dev6",
|
"version": "1.0.5-dev9",
|
||||||
"codename": "aqua",
|
"codename": "aqua",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://git.joinfirefish.org/firefish/firefish.git"
|
"url": "https://git.joinfirefish.org/firefish/firefish.git"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@8.6.11",
|
"packageManager": "pnpm@8.7.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"rebuild": "pnpm run clean && pnpm node ./scripts/build-greet.js && pnpm -r --parallel run build && pnpm run gulp",
|
"rebuild": "pnpm run clean && ./scripts/build-greet.sh && pnpm -r --parallel run build && pnpm run gulp",
|
||||||
"build": "pnpm node ./scripts/build-greet.js && pnpm -r --parallel run build && pnpm run gulp",
|
"build": "./scripts/build-greet.sh && pnpm -r --parallel run build && pnpm run gulp",
|
||||||
"start": "pnpm --filter backend run start",
|
"start": "pnpm --filter backend run start",
|
||||||
"start:test": "pnpm --filter backend run start:test",
|
"start:test": "pnpm --filter backend run start:test",
|
||||||
"init": "pnpm run migrate",
|
"init": "pnpm run migrate",
|
||||||
|
@ -38,18 +38,19 @@
|
||||||
"chokidar": "^3.3.1"
|
"chokidar": "^3.3.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bull-board/api": "5.7.2",
|
"@bull-board/api": "5.8.0",
|
||||||
"@bull-board/ui": "5.7.2",
|
"@bull-board/ui": "5.8.0",
|
||||||
"@napi-rs/cli": "^2.16.2",
|
"@napi-rs/cli": "^2.16.2",
|
||||||
"@tensorflow/tfjs": "^3.21.0",
|
"@tensorflow/tfjs": "^4.10.0",
|
||||||
"js-yaml": "4.1.0",
|
"js-yaml": "4.1.0",
|
||||||
"seedrandom": "^3.0.5"
|
"seedrandom": "^3.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@biomejs/biome": "1.0.0",
|
||||||
"@types/gulp": "4.0.13",
|
"@types/gulp": "4.0.13",
|
||||||
"@types/gulp-rename": "2.0.2",
|
"@types/gulp-rename": "2.0.2",
|
||||||
"@types/node": "20.4.9",
|
"@types/node": "20.5.8",
|
||||||
"chalk": "4.1.2",
|
"add": "2.0.6",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"cypress": "10.11.0",
|
"cypress": "10.11.0",
|
||||||
"execa": "5.1.1",
|
"execa": "5.1.1",
|
||||||
|
@ -59,8 +60,8 @@
|
||||||
"gulp-replace": "1.1.4",
|
"gulp-replace": "1.1.4",
|
||||||
"gulp-terser": "2.1.0",
|
"gulp-terser": "2.1.0",
|
||||||
"install-peers": "^1.0.4",
|
"install-peers": "^1.0.4",
|
||||||
"rome": "^12.1.3",
|
"pnpm": "8.7.1",
|
||||||
"start-server-and-test": "1.15.2",
|
"start-server-and-test": "1.15.2",
|
||||||
"typescript": "5.1.6"
|
"typescript": "5.2.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8 KiB |
1
packages/backend/native-utils/Cargo.lock
generated
|
@ -1305,6 +1305,7 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||||
name = "migration"
|
name = "migration"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"basen",
|
||||||
"futures",
|
"futures",
|
||||||
"indicatif",
|
"indicatif",
|
||||||
"native-utils",
|
"native-utils",
|
||||||
|
|
|
@ -10,11 +10,11 @@ path = "src/lib.rs"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
convert = ["dep:indicatif", "dep:futures"]
|
convert = ["dep:native-utils", "dep:indicatif", "dep:futures"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde_json = "1.0.96"
|
serde_json = "1.0.96"
|
||||||
native-utils = { path = "../" }
|
native-utils = { path = "../", optional = true }
|
||||||
indicatif = { version = "0.17.4", features = ["tokio"], optional = true }
|
indicatif = { version = "0.17.4", features = ["tokio"], optional = true }
|
||||||
tokio = { version = "1.28.2", features = ["full"] }
|
tokio = { version = "1.28.2", features = ["full"] }
|
||||||
futures = { version = "0.3.28", optional = true }
|
futures = { version = "0.3.28", optional = true }
|
||||||
|
@ -24,6 +24,7 @@ urlencoding = "2.1.2"
|
||||||
redis = { version = "0.23.0", features = ["tokio-rustls-comp"] }
|
redis = { version = "0.23.0", features = ["tokio-rustls-comp"] }
|
||||||
sea-orm = "0.11.3"
|
sea-orm = "0.11.3"
|
||||||
url = { version = "2.4.0", features = ["serde"] }
|
url = { version = "2.4.0", features = ["serde"] }
|
||||||
|
basen = "0.1.0"
|
||||||
|
|
||||||
[dependencies.sea-orm-migration]
|
[dependencies.sea-orm-migration]
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
pub use sea_orm_migration::prelude::*;
|
pub use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
|
use basen::BASE36;
|
||||||
|
|
||||||
mod m20230531_180824_drop_reversi;
|
mod m20230531_180824_drop_reversi;
|
||||||
mod m20230627_185451_index_note_url;
|
mod m20230627_185451_index_note_url;
|
||||||
mod m20230709_000510_move_antenna_to_cache;
|
mod m20230709_000510_move_antenna_to_cache;
|
||||||
|
@ -18,3 +20,12 @@ impl MigratorTrait for Migrator {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_timestamp(id: &str) -> i64 {
|
||||||
|
const TIME_2000: i64 = 946_684_800_000;
|
||||||
|
let n: Option<u64> = BASE36.decode_var_len(&id[0..8]);
|
||||||
|
match n {
|
||||||
|
None => -1,
|
||||||
|
Some(n) => n as i64 + TIME_2000,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use native_utils::util::id;
|
|
||||||
use redis::Commands;
|
use redis::Commands;
|
||||||
use sea_orm_migration::prelude::*;
|
use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
|
use crate::get_timestamp;
|
||||||
|
|
||||||
#[derive(DeriveMigrationName)]
|
#[derive(DeriveMigrationName)]
|
||||||
pub struct Migration;
|
pub struct Migration;
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ impl MigrationTrait for Migration {
|
||||||
let all_elems: Vec<Vec<Vec<String>>> = redis_conn.xrange_all(key).unwrap(); // Get all post IDs in stream
|
let all_elems: Vec<Vec<Vec<String>>> = redis_conn.xrange_all(key).unwrap(); // Get all post IDs in stream
|
||||||
let stream_ids = all_elems
|
let stream_ids = all_elems
|
||||||
.iter()
|
.iter()
|
||||||
.map(|v| format!("{}-*", id::get_timestamp(&v[1][1]))); // Get correct stream id with timestamp
|
.map(|v| format!("{}-*", get_timestamp(&v[1][1]))); // Get correct stream id with timestamp
|
||||||
redis_conn.del::<_, ()>(key).unwrap();
|
redis_conn.del::<_, ()>(key).unwrap();
|
||||||
for (j, v) in stream_ids.enumerate() {
|
for (j, v) in stream_ids.enumerate() {
|
||||||
redis_conn
|
redis_conn
|
||||||
|
|
|
@ -42,8 +42,8 @@
|
||||||
"test": "pnpm run cargo:test && pnpm run build:napi && ava",
|
"test": "pnpm run cargo:test && pnpm run build:napi && ava",
|
||||||
"universal": "napi universal",
|
"universal": "napi universal",
|
||||||
"version": "napi version",
|
"version": "napi version",
|
||||||
"format": "cargo fmt --all",
|
"format": "cargo fmt --all -- --check",
|
||||||
"lint": "cargo clippy --fix",
|
"lint": "cargo clippy --fix --allow-dirty --allow-staged && cargo fmt --all -- --check",
|
||||||
"cargo:test": "pnpm run cargo:unit && pnpm run cargo:integration",
|
"cargo:test": "pnpm run cargo:unit && pnpm run cargo:integration",
|
||||||
"cargo:unit": "cargo test unit_test && cargo test -F napi unit_test",
|
"cargo:unit": "cargo test unit_test && cargo test -F napi unit_test",
|
||||||
"cargo:integration": "cargo test -F noarray int_test -- --test-threads=1"
|
"cargo:integration": "cargo test -F noarray int_test -- --test-threads=1"
|
||||||
|
|
|
@ -16,19 +16,19 @@
|
||||||
"build": "pnpm swc src -d built -D",
|
"build": "pnpm swc src -d built -D",
|
||||||
"build:debug": "pnpm swc src -d built -s -D",
|
"build:debug": "pnpm swc src -d built -s -D",
|
||||||
"watch": "pnpm swc src -d built -D -w",
|
"watch": "pnpm swc src -d built -D -w",
|
||||||
"lint": "pnpm rome check --apply *",
|
"lint": "pnpm biome check --apply **/*.ts ; pnpm run format",
|
||||||
"mocha": "cross-env NODE_ENV=test TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_PROJECT=\"./test/tsconfig.json\" mocha",
|
"mocha": "cross-env NODE_ENV=test TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_PROJECT=\"./test/tsconfig.json\" mocha",
|
||||||
"test": "pnpm run mocha",
|
"test": "pnpm run mocha",
|
||||||
"format": "pnpm rome format * --write"
|
"format": "pnpm biome format * --write"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@swc/core-android-arm64": "1.3.11",
|
"@swc/core-android-arm64": "1.3.11",
|
||||||
"@tensorflow/tfjs-node": "3.21.1"
|
"@tensorflow/tfjs-node": "3.21.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bull-board/api": "5.7.2",
|
"@bull-board/api": "5.8.0",
|
||||||
"@bull-board/koa": "5.7.2",
|
"@bull-board/koa": "5.8.0",
|
||||||
"@bull-board/ui": "5.7.2",
|
"@bull-board/ui": "5.8.0",
|
||||||
"@discordapp/twemoji": "14.1.2",
|
"@discordapp/twemoji": "14.1.2",
|
||||||
"@elastic/elasticsearch": "7.17.0",
|
"@elastic/elasticsearch": "7.17.0",
|
||||||
"@koa/cors": "3.4.3",
|
"@koa/cors": "3.4.3",
|
||||||
|
@ -41,17 +41,16 @@
|
||||||
"@tensorflow/tfjs": "^4.2.0",
|
"@tensorflow/tfjs": "^4.2.0",
|
||||||
"adm-zip": "^0.5.10",
|
"adm-zip": "^0.5.10",
|
||||||
"ajv": "8.12.0",
|
"ajv": "8.12.0",
|
||||||
"archiver": "5.3.1",
|
"archiver": "6.0.0",
|
||||||
"argon2": "^0.30.3",
|
"argon2": "^0.31.1",
|
||||||
"autolinker": "4.0.0",
|
"autolinker": "4.0.0",
|
||||||
"autwh": "0.1.0",
|
"autwh": "0.1.0",
|
||||||
"aws-sdk": "2.1413.0",
|
"aws-sdk": "2.1413.0",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"blurhash": "2.0.5",
|
"blurhash": "2.0.5",
|
||||||
"bull": "4.11.2",
|
"bull": "4.11.3",
|
||||||
"cacheable-lookup": "7.0.0",
|
"cacheable-lookup": "TheEssem/cacheable-lookup",
|
||||||
"cbor": "8.1.0",
|
|
||||||
"chalk": "5.3.0",
|
"chalk": "5.3.0",
|
||||||
"chalk-template": "0.4.0",
|
"chalk-template": "0.4.0",
|
||||||
"chokidar": "^3.5.3",
|
"chokidar": "^3.5.3",
|
||||||
|
@ -63,19 +62,19 @@
|
||||||
"deep-email-validator": "0.1.21",
|
"deep-email-validator": "0.1.21",
|
||||||
"escape-regexp": "0.0.1",
|
"escape-regexp": "0.0.1",
|
||||||
"feed": "4.2.2",
|
"feed": "4.2.2",
|
||||||
"file-type": "17.1.6",
|
"file-type": "18.5.0",
|
||||||
"firefish-js": "workspace:*",
|
"firefish-js": "workspace:*",
|
||||||
"fluent-ffmpeg": "2.1.2",
|
"fluent-ffmpeg": "2.1.2",
|
||||||
"got": "12.5.3",
|
"got": "13.0.0",
|
||||||
"gunzip-maybe": "^1.4.2",
|
"gunzip-maybe": "^1.4.2",
|
||||||
"hpagent": "0.1.2",
|
"hpagent": "1.2.0",
|
||||||
"ioredis": "5.3.2",
|
"ioredis": "5.3.2",
|
||||||
"ip-cidr": "3.1.0",
|
"ip-cidr": "3.1.0",
|
||||||
"is-svg": "4.3.2",
|
"is-svg": "5.0.0",
|
||||||
"js-yaml": "4.1.0",
|
"js-yaml": "4.1.0",
|
||||||
"jsdom": "20.0.3",
|
"jsdom": "22.1.0",
|
||||||
"json5": "2.2.3",
|
"json5": "2.2.3",
|
||||||
"jsonld": "8.2.0",
|
"jsonld": "8.2.1",
|
||||||
"jsrsasign": "10.8.6",
|
"jsrsasign": "10.8.6",
|
||||||
"koa": "2.14.2",
|
"koa": "2.14.2",
|
||||||
"koa-body": "^6.0.1",
|
"koa-body": "^6.0.1",
|
||||||
|
@ -89,10 +88,10 @@
|
||||||
"koa-slow": "2.1.0",
|
"koa-slow": "2.1.0",
|
||||||
"koa-views": "7.0.2",
|
"koa-views": "7.0.2",
|
||||||
"megalodon": "workspace:*",
|
"megalodon": "workspace:*",
|
||||||
"meilisearch": "0.33.0",
|
"meilisearch": "0.34.1",
|
||||||
"mfm-js": "0.23.3",
|
"mfm-js": "0.23.3",
|
||||||
"mime-types": "2.1.35",
|
"mime-types": "2.1.35",
|
||||||
"msgpackr": "1.9.6",
|
"msgpackr": "1.9.7",
|
||||||
"multer": "1.4.4-lts.1",
|
"multer": "1.4.4-lts.1",
|
||||||
"native-utils": "link:native-utils",
|
"native-utils": "link:native-utils",
|
||||||
"nested-property": "4.0.0",
|
"nested-property": "4.0.0",
|
||||||
|
@ -100,22 +99,22 @@
|
||||||
"nodemailer": "6.9.4",
|
"nodemailer": "6.9.4",
|
||||||
"nsfwjs": "2.4.2",
|
"nsfwjs": "2.4.2",
|
||||||
"oauth": "^0.10.0",
|
"oauth": "^0.10.0",
|
||||||
|
"opencc-js": "^1.0.5",
|
||||||
"os-utils": "0.0.14",
|
"os-utils": "0.0.14",
|
||||||
"otpauth": "^9.1.4",
|
"otpauth": "^9.1.4",
|
||||||
"parse5": "7.1.2",
|
"parse5": "7.1.2",
|
||||||
"pg": "8.11.2",
|
"pg": "8.11.3",
|
||||||
"private-ip": "2.3.4",
|
"private-ip": "3.0.1",
|
||||||
"probe-image-size": "7.2.3",
|
"probe-image-size": "7.2.3",
|
||||||
"promise-limit": "2.7.0",
|
"promise-limit": "2.7.0",
|
||||||
"punycode": "2.3.0",
|
"punycode": "2.3.0",
|
||||||
"pureimage": "0.3.15",
|
"pureimage": "0.4.8",
|
||||||
"qrcode": "1.5.3",
|
"qrcode": "1.5.3",
|
||||||
"qs": "6.11.2",
|
"qs": "6.11.2",
|
||||||
"random-seed": "0.3.0",
|
"random-seed": "0.3.0",
|
||||||
"ratelimiter": "3.4.1",
|
"ratelimiter": "3.4.1",
|
||||||
"re2": "1.20.1",
|
"re2": "1.20.3",
|
||||||
"redis-lock": "0.1.4",
|
"redis-semaphore": "5.5.0",
|
||||||
"redis-semaphore": "5.4.0",
|
|
||||||
"reflect-metadata": "0.1.13",
|
"reflect-metadata": "0.1.13",
|
||||||
"rename": "1.0.4",
|
"rename": "1.0.4",
|
||||||
"rndstr": "1.0.0",
|
"rndstr": "1.0.0",
|
||||||
|
@ -123,12 +122,12 @@
|
||||||
"sanitize-html": "2.11.0",
|
"sanitize-html": "2.11.0",
|
||||||
"seedrandom": "^3.0.5",
|
"seedrandom": "^3.0.5",
|
||||||
"semver": "7.5.4",
|
"semver": "7.5.4",
|
||||||
"sharp": "0.32.4",
|
"sharp": "0.32.5",
|
||||||
"sonic-channel": "^1.3.1",
|
"sonic-channel": "^1.3.1",
|
||||||
"stringz": "2.1.0",
|
"stringz": "2.1.0",
|
||||||
"summaly": "2.7.0",
|
"summaly": "2.7.0",
|
||||||
"syslog-pro": "1.0.0",
|
"syslog-pro": "1.0.0",
|
||||||
"systeminformation": "5.18.13",
|
"systeminformation": "5.21.3",
|
||||||
"tar-stream": "^3.1.6",
|
"tar-stream": "^3.1.6",
|
||||||
"tesseract.js": "^4.1.1",
|
"tesseract.js": "^4.1.1",
|
||||||
"tinycolor2": "1.6.0",
|
"tinycolor2": "1.6.0",
|
||||||
|
@ -137,7 +136,7 @@
|
||||||
"typeorm": "0.3.17",
|
"typeorm": "0.3.17",
|
||||||
"ulid": "2.3.0",
|
"ulid": "2.3.0",
|
||||||
"uuid": "9.0.0",
|
"uuid": "9.0.0",
|
||||||
"web-push": "3.6.4",
|
"web-push": "3.6.5",
|
||||||
"websocket": "1.0.34",
|
"websocket": "1.0.34",
|
||||||
"xev": "3.0.2"
|
"xev": "3.0.2"
|
||||||
},
|
},
|
||||||
|
@ -146,7 +145,6 @@
|
||||||
"@swc/core": "^1.3.75",
|
"@swc/core": "^1.3.75",
|
||||||
"@types/adm-zip": "^0.5.0",
|
"@types/adm-zip": "^0.5.0",
|
||||||
"@types/bcryptjs": "2.4.2",
|
"@types/bcryptjs": "2.4.2",
|
||||||
"@types/cbor": "6.0.0",
|
|
||||||
"@types/escape-regexp": "0.0.1",
|
"@types/escape-regexp": "0.0.1",
|
||||||
"@types/fluent-ffmpeg": "2.1.21",
|
"@types/fluent-ffmpeg": "2.1.21",
|
||||||
"@types/js-yaml": "4.0.5",
|
"@types/js-yaml": "4.0.5",
|
||||||
|
|
|
@ -30,40 +30,34 @@ const themeColor = chalk.hex("#31748f");
|
||||||
function greet() {
|
function greet() {
|
||||||
if (!envOption.quiet) {
|
if (!envOption.quiet) {
|
||||||
//#region Firefish logo
|
//#region Firefish logo
|
||||||
const v = `v${meta.version}`;
|
|
||||||
console.log(
|
console.log(
|
||||||
themeColor(
|
themeColor(
|
||||||
" ▄▄▄▄▄▄▄ ▄▄▄ ▄▄▄▄▄▄ ▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄ ▄▄▄ ▄▄▄▄▄▄▄ ▄▄ ▄▄ ◯ ",
|
"██████╗ ██╗██████╗ ███████╗███████╗██╗███████╗██╗ ██╗ ○ ▄ ▄ ",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
console.log(
|
console.log(
|
||||||
themeColor(
|
themeColor(
|
||||||
"█ █ █ ▄ █ █ █ █ █ █ █ █ █ ○ ▄ ▄",
|
"██╔════╝██║██╔══██╗██╔════╝██╔════╝██║██╔════╝██║ ██║ ⚬ █▄▄ █▄▄ ",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
console.log(
|
console.log(
|
||||||
themeColor(
|
themeColor(
|
||||||
"█ ▄▄▄█ █ █ █ █ █ ▄▄▄█ ▄▄▄█ █ ▄▄▄▄▄█ █▄█ █ ⚬ █▄▄ █▄▄ ",
|
"█████╗ ██║██████╔╝█████╗ █████╗ ██║███████╗███████║ ▄▄▄▄▄▄ ▄ ",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
console.log(
|
console.log(
|
||||||
themeColor(
|
themeColor(
|
||||||
"█ █▄▄▄█ █ █▄▄█▄█ █▄▄▄█ █▄▄▄█ █ █▄▄▄▄▄█ █ ▄▄▄▄▄▄ ▄",
|
"██╔══╝ ██║██╔══██╗██╔══╝ ██╔══╝ ██║╚════██║██╔══██║ █ █ █▄▄ ",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
console.log(
|
console.log(
|
||||||
themeColor(
|
themeColor(
|
||||||
"█ ▄▄▄█ █ ▄▄ █ ▄▄▄█ ▄▄▄█ █▄▄▄▄▄ █ ▄ █ █ █ █▄▄",
|
"██║ ██║██║ ██║███████╗██║ ██║███████║██║ ██║ █ ● ● █ ",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
console.log(
|
console.log(
|
||||||
themeColor(
|
themeColor(
|
||||||
"█ █ █ █ █ █ █ █▄▄▄█ █ █ █▄▄▄▄▄█ █ █ █ █ █ ● ● █",
|
"╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ▀▄▄▄▄▄▄▀ ",
|
||||||
),
|
|
||||||
);
|
|
||||||
console.log(
|
|
||||||
themeColor(
|
|
||||||
"█▄▄▄█ █▄▄▄█▄▄▄█ █▄█▄▄▄▄▄▄▄█▄▄▄█ █▄▄▄█▄▄▄▄▄▄▄█▄▄█ █▄▄█ ▀▄▄▄▄▄▄▀",
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
|
@ -70,6 +70,8 @@ if (hasConfig) {
|
||||||
"of",
|
"of",
|
||||||
"they",
|
"they",
|
||||||
"these",
|
"these",
|
||||||
|
"is",
|
||||||
|
"are",
|
||||||
"これ",
|
"これ",
|
||||||
"それ",
|
"それ",
|
||||||
"あれ",
|
"あれ",
|
||||||
|
@ -81,37 +83,30 @@ if (hasConfig) {
|
||||||
"あそこ",
|
"あそこ",
|
||||||
"こちら",
|
"こちら",
|
||||||
"どこ",
|
"どこ",
|
||||||
"だれ",
|
|
||||||
"なに",
|
|
||||||
"なん",
|
|
||||||
"何",
|
|
||||||
"私",
|
"私",
|
||||||
"貴方",
|
"僕",
|
||||||
"貴方方",
|
"俺",
|
||||||
|
"君",
|
||||||
|
"あなた",
|
||||||
"我々",
|
"我々",
|
||||||
"私達",
|
"私達",
|
||||||
"あの人",
|
|
||||||
"あのか",
|
|
||||||
"彼女",
|
"彼女",
|
||||||
"彼",
|
"彼",
|
||||||
"です",
|
"です",
|
||||||
"ありま",
|
"ます",
|
||||||
"おりま",
|
|
||||||
"います",
|
|
||||||
"は",
|
"は",
|
||||||
"が",
|
"が",
|
||||||
"の",
|
"の",
|
||||||
"に",
|
"に",
|
||||||
"を",
|
"を",
|
||||||
"で",
|
"で",
|
||||||
"え",
|
"へ",
|
||||||
"から",
|
"から",
|
||||||
"まで",
|
"まで",
|
||||||
"より",
|
"より",
|
||||||
"も",
|
"も",
|
||||||
"どの",
|
"どの",
|
||||||
"と",
|
"と",
|
||||||
"し",
|
|
||||||
"それで",
|
"それで",
|
||||||
"しかし",
|
"しかし",
|
||||||
])
|
])
|
||||||
|
|
2
packages/backend/src/global.d.ts
vendored
|
@ -1,2 +1,2 @@
|
||||||
// rome-ignore lint/suspicious/noExplicitAny: i have no idea
|
// biome-ignore lint/suspicious/noExplicitAny: i have no idea
|
||||||
type FIXME = any;
|
type FIXME = any;
|
||||||
|
|
|
@ -1,33 +1,40 @@
|
||||||
import { redisClient } from "../db/redis.js";
|
import { redisClient } from "../db/redis.js";
|
||||||
import { promisify } from "node:util";
|
import { Mutex } from "redis-semaphore";
|
||||||
import redisLock from "redis-lock";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retry delay (ms) for lock acquisition
|
* Retry delay (ms) for lock acquisition
|
||||||
*/
|
*/
|
||||||
const retryDelay = 100;
|
const retryDelay = 100;
|
||||||
|
|
||||||
const lock: (key: string, timeout?: number) => Promise<() => void> = redisClient
|
|
||||||
? promisify(redisLock(redisClient, retryDelay))
|
|
||||||
: async () => () => {};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get AP Object lock
|
* Get AP Object lock
|
||||||
* @param uri AP object ID
|
* @param uri AP object ID
|
||||||
* @param timeout Lock timeout (ms), The timeout releases previous lock.
|
* @param timeout Lock timeout (ms), The timeout releases previous lock.
|
||||||
* @returns Unlock function
|
* @returns Unlock function
|
||||||
*/
|
*/
|
||||||
export function getApLock(uri: string, timeout = 30 * 1000) {
|
export async function getApLock(uri: string, timeout = 30 * 1000) {
|
||||||
return lock(`ap-object:${uri}`, timeout);
|
const lock = new Mutex(redisClient, `ap-object:${uri}`, {
|
||||||
|
lockTimeout: timeout,
|
||||||
|
retryInterval: retryDelay,
|
||||||
|
});
|
||||||
|
await lock.acquire();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFetchInstanceMetadataLock(
|
export async function getFetchInstanceMetadataLock(
|
||||||
host: string,
|
host: string,
|
||||||
timeout = 30 * 1000,
|
timeout = 30 * 1000,
|
||||||
) {
|
) {
|
||||||
return lock(`instance:${host}`, timeout);
|
const lock = new Mutex(redisClient, `instance:${host}`, {
|
||||||
|
lockTimeout: timeout,
|
||||||
|
retryInterval: retryDelay,
|
||||||
|
});
|
||||||
|
await lock.acquire();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getChartInsertLock(lockKey: string, timeout = 30 * 1000) {
|
export async function getChartInsertLock(lockKey: string, timeout = 30 * 1000) {
|
||||||
return lock(`chart-insert:${lockKey}`, timeout);
|
const lock = new Mutex(redisClient, `chart-insert:${lockKey}`, {
|
||||||
|
lockTimeout: timeout,
|
||||||
|
retryInterval: retryDelay,
|
||||||
|
});
|
||||||
|
await lock.acquire();
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,8 +32,6 @@ export default async function (
|
||||||
// Interrupt if you block the announcement destination
|
// Interrupt if you block the announcement destination
|
||||||
if (await shouldBlockInstance(extractDbHost(uri))) return;
|
if (await shouldBlockInstance(extractDbHost(uri))) return;
|
||||||
|
|
||||||
const unlock = await getApLock(uri);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Check if something with the same URI is already registered
|
// Check if something with the same URI is already registered
|
||||||
const exist = await fetchNote(uri);
|
const exist = await fetchNote(uri);
|
||||||
|
@ -60,9 +58,10 @@ export default async function (
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(await Notes.isVisibleForMe(renote, actor.id)))
|
if (renote != null && !(await Notes.isVisibleForMe(renote, actor.id))) {
|
||||||
return "skip: invalid actor for this activity";
|
console.log("skip: invalid actor for this activity");
|
||||||
|
return;
|
||||||
|
}
|
||||||
logger.info(`Creating the (Re)Note: ${uri}`);
|
logger.info(`Creating the (Re)Note: ${uri}`);
|
||||||
|
|
||||||
const activityAudience = await parseAudience(
|
const activityAudience = await parseAudience(
|
||||||
|
@ -79,6 +78,6 @@ export default async function (
|
||||||
uri,
|
uri,
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
unlock();
|
await getApLock(uri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,8 +31,6 @@ export default async function (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const unlock = await getApLock(uri);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const exist = await fetchNote(note);
|
const exist = await fetchNote(note);
|
||||||
if (exist) return "skip: note exists";
|
if (exist) return "skip: note exists";
|
||||||
|
@ -46,6 +44,6 @@ export default async function (
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
unlock();
|
await getApLock(uri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,6 @@ export default async function (
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
logger.info(`Deleting the Note: ${uri}`);
|
logger.info(`Deleting the Note: ${uri}`);
|
||||||
|
|
||||||
const unlock = await getApLock(uri);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const dbResolver = new DbResolver();
|
const dbResolver = new DbResolver();
|
||||||
const note = await dbResolver.getNoteFromApId(uri);
|
const note = await dbResolver.getNoteFromApId(uri);
|
||||||
|
@ -39,6 +37,6 @@ export default async function (
|
||||||
await deleteNode(actor, note);
|
await deleteNode(actor, note);
|
||||||
return "ok: note deleted";
|
return "ok: note deleted";
|
||||||
} finally {
|
} finally {
|
||||||
unlock();
|
await getApLock(uri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,13 +68,13 @@ export class LdSignature {
|
||||||
...options,
|
...options,
|
||||||
"@context": "https://w3id.org/identity/v1",
|
"@context": "https://w3id.org/identity/v1",
|
||||||
};
|
};
|
||||||
transformedOptions.type = undefined;
|
delete transformedOptions["type"];
|
||||||
transformedOptions.id = undefined;
|
delete transformedOptions["id"];
|
||||||
transformedOptions.signatureValue = undefined;
|
delete transformedOptions["signatureValue"];
|
||||||
const canonizedOptions = await this.normalize(transformedOptions);
|
const canonizedOptions = await this.normalize(transformedOptions);
|
||||||
const optionsHash = this.sha256(canonizedOptions);
|
const optionsHash = this.sha256(canonizedOptions);
|
||||||
const transformedData = { ...data };
|
const transformedData = { ...data };
|
||||||
transformedData.signature = undefined;
|
delete transformedData["signature"];
|
||||||
const cannonidedData = await this.normalize(transformedData);
|
const cannonidedData = await this.normalize(transformedData);
|
||||||
if (this.debug) console.debug(`cannonidedData: ${cannonidedData}`);
|
if (this.debug) console.debug(`cannonidedData: ${cannonidedData}`);
|
||||||
const documentHash = this.sha256(cannonidedData);
|
const documentHash = this.sha256(cannonidedData);
|
||||||
|
|
|
@ -415,8 +415,6 @@ export async function resolveNote(
|
||||||
`host ${extractDbHost(uri)} is blocked`,
|
`host ${extractDbHost(uri)} is blocked`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const unlock = await getApLock(uri);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//#region Returns if already registered with this server
|
//#region Returns if already registered with this server
|
||||||
const exist = await fetchNote(uri);
|
const exist = await fetchNote(uri);
|
||||||
|
@ -439,7 +437,7 @@ export async function resolveNote(
|
||||||
// Since the attached Note Object may be disguised, always specify the uri and fetch it from the server.
|
// Since the attached Note Object may be disguised, always specify the uri and fetch it from the server.
|
||||||
return await createNote(uri, resolver, true);
|
return await createNote(uri, resolver, true);
|
||||||
} finally {
|
} finally {
|
||||||
unlock();
|
await getApLock(uri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { promisify } from "node:util";
|
import { decode } from "msgpackr";
|
||||||
import * as cbor from "cbor";
|
|
||||||
import define from "../../../define.js";
|
import define from "../../../define.js";
|
||||||
import {
|
import {
|
||||||
UserProfiles,
|
UserProfiles,
|
||||||
|
@ -12,7 +11,6 @@ import { procedures, hash } from "../../../2fa.js";
|
||||||
import { publishMainStream } from "@/services/stream.js";
|
import { publishMainStream } from "@/services/stream.js";
|
||||||
import { comparePassword } from "@/misc/password.js";
|
import { comparePassword } from "@/misc/password.js";
|
||||||
|
|
||||||
const cborDecodeFirst = promisify(cbor.decodeFirst) as any;
|
|
||||||
const rpIdHashReal = hash(Buffer.from(config.hostname, "utf-8"));
|
const rpIdHashReal = hash(Buffer.from(config.hostname, "utf-8"));
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
|
@ -64,7 +62,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
|
|
||||||
const clientDataJSONHash = hash(Buffer.from(ps.clientDataJSON, "utf-8"));
|
const clientDataJSONHash = hash(Buffer.from(ps.clientDataJSON, "utf-8"));
|
||||||
|
|
||||||
const attestation = await cborDecodeFirst(ps.attestationObject);
|
const attestation = decode(Buffer.from(ps.attestationObject, "utf-8"));
|
||||||
|
|
||||||
const rpIdHash = attestation.authData.slice(0, 32);
|
const rpIdHash = attestation.authData.slice(0, 32);
|
||||||
if (!rpIdHashReal.equals(rpIdHash)) {
|
if (!rpIdHashReal.equals(rpIdHash)) {
|
||||||
|
@ -81,7 +79,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
const credentialIdLength = authData.readUInt16BE(53);
|
const credentialIdLength = authData.readUInt16BE(53);
|
||||||
const credentialId = authData.slice(55, 55 + credentialIdLength);
|
const credentialId = authData.slice(55, 55 + credentialIdLength);
|
||||||
const publicKeyData = authData.slice(55 + credentialIdLength);
|
const publicKeyData = authData.slice(55 + credentialIdLength);
|
||||||
const publicKey: Map<number, any> = await cborDecodeFirst(publicKeyData);
|
const publicKey: Map<number, any> = decode(publicKeyData);
|
||||||
if (publicKey.get(3) !== -7) {
|
if (publicKey.get(3) !== -7) {
|
||||||
throw new Error("alg mismatch");
|
throw new Error("alg mismatch");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { URLSearchParams } from "node:url";
|
import { URLSearchParams } from "node:url";
|
||||||
import fetch from "node-fetch";
|
import fetch from "node-fetch";
|
||||||
import config from "@/config/index.js";
|
import config from "@/config/index.js";
|
||||||
|
import { Converter } from "opencc-js";
|
||||||
import { getAgentByUrl } from "@/misc/fetch.js";
|
import { getAgentByUrl } from "@/misc/fetch.js";
|
||||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||||
import { Notes } from "@/models/index.js";
|
import { Notes } from "@/models/index.js";
|
||||||
|
@ -38,6 +39,13 @@ export const paramDef = {
|
||||||
required: ["noteId", "targetLang"],
|
required: ["noteId", "targetLang"],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
function convertChinese(convert: boolean, src: string) {
|
||||||
|
if (!convert) return src;
|
||||||
|
|
||||||
|
const converter = Converter({ from: "cn", to: "twp" });
|
||||||
|
return converter(src);
|
||||||
|
}
|
||||||
|
|
||||||
export default define(meta, paramDef, async (ps, user) => {
|
export default define(meta, paramDef, async (ps, user) => {
|
||||||
const note = await getNote(ps.noteId, user).catch((err) => {
|
const note = await getNote(ps.noteId, user).catch((err) => {
|
||||||
if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24")
|
if (err.id === "9725d0ce-ba28-4dde-95a7-2cbb2c15de24")
|
||||||
|
@ -93,7 +101,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
sourceLang: json.detectedLanguage?.language,
|
sourceLang: json.detectedLanguage?.language,
|
||||||
text: json.translatedText,
|
text: convertChinese(ps.targetLang === "zh-TW", json.translatedText),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,6 +136,6 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
sourceLang: json.translations[0].detected_source_language,
|
sourceLang: json.translations[0].detected_source_language,
|
||||||
text: json.translations[0].text,
|
text: convertChinese(ps.targetLang === "zh-TW", json.translations[0].text),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -59,7 +59,6 @@ export default class Connection {
|
||||||
accessToken: string,
|
accessToken: string,
|
||||||
prepareStream: string | undefined,
|
prepareStream: string | undefined,
|
||||||
) {
|
) {
|
||||||
console.log("constructor", prepareStream);
|
|
||||||
this.wsConnection = wsConnection;
|
this.wsConnection = wsConnection;
|
||||||
this.subscriber = subscriber;
|
this.subscriber = subscriber;
|
||||||
if (user) this.user = user;
|
if (user) this.user = user;
|
||||||
|
@ -88,7 +87,6 @@ export default class Connection {
|
||||||
|
|
||||||
this.subscriber.on(`user:${this.user.id}`, this.onUserEvent);
|
this.subscriber.on(`user:${this.user.id}`, this.onUserEvent);
|
||||||
}
|
}
|
||||||
console.log("prepare", prepareStream);
|
|
||||||
if (prepareStream) {
|
if (prepareStream) {
|
||||||
this.onWsConnectionMessage({
|
this.onWsConnectionMessage({
|
||||||
type: "utf8",
|
type: "utf8",
|
||||||
|
@ -185,8 +183,7 @@ export default class Connection {
|
||||||
const tl = await client.getHomeTimeline();
|
const tl = await client.getHomeTimeline();
|
||||||
for (const t of tl.data) forSubscribe.push(t.id);
|
for (const t of tl.data) forSubscribe.push(t.id);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.log(e);
|
console.error(e);
|
||||||
console.error(e.response.data);
|
|
||||||
}
|
}
|
||||||
} else if (simpleObj.stream === "public:local") {
|
} else if (simpleObj.stream === "public:local") {
|
||||||
this.currentSubscribe.push(["public:local"]);
|
this.currentSubscribe.push(["public:local"]);
|
||||||
|
@ -247,7 +244,6 @@ export default class Connection {
|
||||||
|
|
||||||
for (const obj of objs) {
|
for (const obj of objs) {
|
||||||
const { type, body } = obj;
|
const { type, body } = obj;
|
||||||
// console.log(type, body);
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "readNotification":
|
case "readNotification":
|
||||||
this.onReadNotification(body);
|
this.onReadNotification(body);
|
||||||
|
|
|
@ -3,10 +3,11 @@
|
||||||
"name": "Firefish",
|
"name": "Firefish",
|
||||||
"description": "An open source, decentralized social media platform that's free forever!",
|
"description": "An open source, decentralized social media platform that's free forever!",
|
||||||
"start_url": "/",
|
"start_url": "/",
|
||||||
|
"scope": "/",
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"background_color": "#1f1d2e",
|
"background_color": "#1f1d2e",
|
||||||
"theme_color": "#31748f",
|
"theme_color": "#31748f",
|
||||||
"orientation": "portrait-primary",
|
"orientation": "natural",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "/static-assets/icons/192.png",
|
"src": "/static-assets/icons/192.png",
|
||||||
|
@ -21,7 +22,7 @@
|
||||||
"purpose": "any"
|
"purpose": "any"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "/static-assets/icons/maskable.png",
|
"src": "/static-assets/icons/512.png",
|
||||||
"sizes": "512x512",
|
"sizes": "512x512",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"purpose": "maskable"
|
"purpose": "maskable"
|
||||||
|
|
|
@ -11,7 +11,6 @@ export const manifestHandler = async (ctx: Koa.Context) => {
|
||||||
const instance = await fetchMeta(true);
|
const instance = await fetchMeta(true);
|
||||||
|
|
||||||
res.short_name = instance.name || "Firefish";
|
res.short_name = instance.name || "Firefish";
|
||||||
res.name = instance.name || "Firefish";
|
|
||||||
if (instance.themeColor) res.theme_color = instance.themeColor;
|
if (instance.themeColor) res.theme_color = instance.themeColor;
|
||||||
for (const icon of res.icons) {
|
for (const icon of res.icons) {
|
||||||
icon.src = `${icon.src}?v=${config.version.replace(/[^0-9]/g, "")}`;
|
icon.src = `${icon.src}?v=${config.version.replace(/[^0-9]/g, "")}`;
|
||||||
|
|
|
@ -7,16 +7,16 @@ doctype html
|
||||||
|
|
||||||
//
|
//
|
||||||
-
|
-
|
||||||
▄▄▄▄▄▄▄ ▄▄▄ ▄▄▄▄▄▄ ▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄ ▄▄▄ ▄▄▄▄▄▄▄ ▄▄ ▄▄ ◯
|
|
||||||
█ █ █ ▄ █ █ █ █ █ █ █ █ █ ○ ▄ ▄
|
██████╗ ██╗██████╗ ███████╗███████╗██╗███████╗██╗ ██╗ ○ ▄ ▄
|
||||||
█ ▄▄▄█ █ █ █ █ █ ▄▄▄█ ▄▄▄█ █ ▄▄▄▄▄█ █▄█ █ ⚬ █▄▄ █▄▄
|
██╔════╝██║██╔══██╗██╔════╝██╔════╝██║██╔════╝██║ ██║ ⚬ █▄▄ █▄▄
|
||||||
█ █▄▄▄█ █ █▄▄█▄█ █▄▄▄█ █▄▄▄█ █ █▄▄▄▄▄█ █ ▄▄▄▄▄▄ ▄
|
█████╗ ██║██████╔╝█████╗ █████╗ ██║███████╗███████║ ▄▄▄▄▄▄ ▄
|
||||||
█ ▄▄▄█ █ ▄▄ █ ▄▄▄█ ▄▄▄█ █▄▄▄▄▄ █ ▄ █ █ █ █▄▄
|
██╔══╝ ██║██╔══██╗██╔══╝ ██╔══╝ ██║╚════██║██╔══██║ █ █ █▄▄
|
||||||
█ █ █ █ █ █ █ █▄▄▄█ █ █ █▄▄▄▄▄█ █ █ █ █ █ ● ● █
|
██║ ██║██║ ██║███████╗██║ ██║███████║██║ ██║ █ ● ● █
|
||||||
█▄▄▄█ █▄▄▄█▄▄▄█ █▄█▄▄▄▄▄▄▄█▄▄▄█ █▄▄▄█▄▄▄▄▄▄▄█▄▄█ █▄▄█ ▀▄▄▄▄▄▄▀
|
╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ▀▄▄▄▄▄▄▀
|
||||||
|
|
||||||
Thank you for using Firefish!
|
Thank you for using Firefish!
|
||||||
If you are reading this message... how about joining the development?
|
If you're reading this message... how about helping out with development?
|
||||||
https://git.joinfirefish.org/firefish/firefish
|
https://git.joinfirefish.org/firefish/firefish
|
||||||
|
|
||||||
html
|
html
|
||||||
|
|
|
@ -430,7 +430,6 @@ export default abstract class Chart<T extends Schema> {
|
||||||
? `${this.name}:${date}:${span}:${group}`
|
? `${this.name}:${date}:${span}:${group}`
|
||||||
: `${this.name}:${date}:${span}`;
|
: `${this.name}:${date}:${span}`;
|
||||||
|
|
||||||
const unlock = await getChartInsertLock(lockKey);
|
|
||||||
try {
|
try {
|
||||||
// ロック内でもう1回チェックする
|
// ロック内でもう1回チェックする
|
||||||
const currentLog = (await repository.findOneBy({
|
const currentLog = (await repository.findOneBy({
|
||||||
|
@ -466,14 +465,14 @@ export default abstract class Chart<T extends Schema> {
|
||||||
|
|
||||||
return log;
|
return log;
|
||||||
} finally {
|
} finally {
|
||||||
unlock();
|
await getChartInsertLock(lockKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected commit(diff: Commit<T>, group: string | null = null): void {
|
protected commit(diff: Commit<T>, group: string | null = null): void {
|
||||||
for (const [k, v] of Object.entries(diff)) {
|
for (const [k, v] of Object.entries(diff)) {
|
||||||
if (v == null || v === 0 || (Array.isArray(v) && v.length === 0))
|
if (v == null || v === 0 || (Array.isArray(v) && v.length === 0))
|
||||||
// rome-ignore lint/performance/noDelete: needs to be deleted not just set to undefined
|
// biome-ignore lint/performance/noDelete: needs to be deleted not just set to undefined
|
||||||
delete diff[k];
|
delete diff[k];
|
||||||
}
|
}
|
||||||
this.buffer.push({
|
this.buffer.push({
|
||||||
|
|
|
@ -15,8 +15,6 @@ export async function fetchInstanceMetadata(
|
||||||
instance: Instance,
|
instance: Instance,
|
||||||
force = false,
|
force = false,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const unlock = await getFetchInstanceMetadataLock(instance.host);
|
|
||||||
|
|
||||||
if (!force) {
|
if (!force) {
|
||||||
const _instance = await Instances.findOneBy({ host: instance.host });
|
const _instance = await Instances.findOneBy({ host: instance.host });
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
|
@ -24,7 +22,7 @@ export async function fetchInstanceMetadata(
|
||||||
_instance?.infoUpdatedAt &&
|
_instance?.infoUpdatedAt &&
|
||||||
now - _instance.infoUpdatedAt.getTime() < 1000 * 60 * 60 * 24
|
now - _instance.infoUpdatedAt.getTime() < 1000 * 60 * 60 * 24
|
||||||
) {
|
) {
|
||||||
unlock();
|
await getFetchInstanceMetadataLock(instance.host);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +51,7 @@ export async function fetchInstanceMetadata(
|
||||||
} as Record<string, any>;
|
} as Record<string, any>;
|
||||||
|
|
||||||
if (info) {
|
if (info) {
|
||||||
updates.softwareName = info.software?.name.toLowerCase();
|
updates.softwareName = info.software?.name?.toLowerCase() || null;
|
||||||
updates.softwareVersion = info.software?.version;
|
updates.softwareVersion = info.software?.version;
|
||||||
updates.openRegistrations = info.openRegistrations;
|
updates.openRegistrations = info.openRegistrations;
|
||||||
updates.maintainerName = info.metadata
|
updates.maintainerName = info.metadata
|
||||||
|
@ -80,24 +78,24 @@ export async function fetchInstanceMetadata(
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(`Failed to update metadata of ${instance.host}: ${e}`);
|
logger.error(`Failed to update metadata of ${instance.host}: ${e}`);
|
||||||
} finally {
|
} finally {
|
||||||
unlock();
|
await getFetchInstanceMetadataLock(instance.host);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type NodeInfo = {
|
type NodeInfo = {
|
||||||
openRegistrations?: any;
|
openRegistrations?: boolean;
|
||||||
software?: {
|
software?: {
|
||||||
name?: any;
|
name?: string;
|
||||||
version?: any;
|
version?: string;
|
||||||
};
|
};
|
||||||
metadata?: {
|
metadata?: {
|
||||||
name?: any;
|
name?: string;
|
||||||
nodeName?: any;
|
nodeName?: string;
|
||||||
nodeDescription?: any;
|
nodeDescription?: string;
|
||||||
description?: any;
|
description?: string;
|
||||||
maintainer?: {
|
maintainer?: {
|
||||||
name?: any;
|
name?: string;
|
||||||
email?: any;
|
email?: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -169,7 +169,7 @@ export default async (
|
||||||
data: Option,
|
data: Option,
|
||||||
silent = false,
|
silent = false,
|
||||||
) =>
|
) =>
|
||||||
// rome-ignore lint/suspicious/noAsyncPromiseExecutor: FIXME
|
// biome-ignore lint/suspicious/noAsyncPromiseExecutor: FIXME
|
||||||
new Promise<Note>(async (res, rej) => {
|
new Promise<Note>(async (res, rej) => {
|
||||||
const dontFederateInitially = data.visibility === "hidden";
|
const dontFederateInitially = data.visibility === "hidden";
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"extends": ["@eslint-sets/vue3", "@eslint-sets/vue3-ts"],
|
"extends": ["@eslint-sets/vue3", "@eslint-sets/vue3-ts"],
|
||||||
"plugins": ["file-progress", "prettier"],
|
"plugins": ["file-progress", "prettier"],
|
||||||
|
"ignorePatterns": ["**/*.json5"],
|
||||||
"rules": {
|
"rules": {
|
||||||
"file-progress/activate": 1
|
"file-progress/activate": 1
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
"watch": "pnpm vite build --watch --mode development",
|
"watch": "pnpm vite build --watch --mode development",
|
||||||
"build": "pnpm vite build",
|
"build": "pnpm vite build",
|
||||||
"build:debug": "pnpm run build",
|
"build:debug": "pnpm run build",
|
||||||
"lint": "pnpm rome check **/*.ts --apply && pnpm run lint:vue",
|
"lint": "pnpm biome check **/*.ts --apply ; pnpm run lint:vue",
|
||||||
"lint:vue": "pnpm paralint --ext .vue --fix '**/*.vue' --cache",
|
"lint:vue": "pnpm eslint src --fix '**/*.vue' --cache ; pnpm run format",
|
||||||
"format": "pnpm rome format * --write && pnpm prettier --write '**/*.{scss,vue}' --cache --cache-strategy metadata"
|
"format": "pnpm biome format * --write && pnpm prettier --write '**/*.{scss,vue}' --cache --cache-strategy metadata"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@discordapp/twemoji": "14.1.2",
|
"@discordapp/twemoji": "14.1.2",
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
"@phosphor-icons/web": "^2.0.3",
|
"@phosphor-icons/web": "^2.0.3",
|
||||||
"@rollup/plugin-alias": "5.0.0",
|
"@rollup/plugin-alias": "5.0.0",
|
||||||
"@rollup/plugin-json": "6.0.0",
|
"@rollup/plugin-json": "6.0.0",
|
||||||
"@rollup/pluginutils": "^5.0.3",
|
"@rollup/pluginutils": "^5.0.4",
|
||||||
"@syuilo/aiscript": "0.11.1",
|
"@syuilo/aiscript": "0.11.1",
|
||||||
"@types/escape-regexp": "0.0.1",
|
"@types/escape-regexp": "0.0.1",
|
||||||
"@types/glob": "8.1.0",
|
"@types/glob": "8.1.0",
|
||||||
|
@ -28,15 +28,15 @@
|
||||||
"@types/seedrandom": "3.0.5",
|
"@types/seedrandom": "3.0.5",
|
||||||
"@types/throttle-debounce": "5.0.0",
|
"@types/throttle-debounce": "5.0.0",
|
||||||
"@types/tinycolor2": "1.4.3",
|
"@types/tinycolor2": "1.4.3",
|
||||||
"@types/uuid": "9.0.2",
|
"@types/uuid": "9.0.3",
|
||||||
"@vitejs/plugin-vue": "4.3.1",
|
"@vitejs/plugin-vue": "4.3.4",
|
||||||
"@vue/compiler-sfc": "3.3.4",
|
"@vue/compiler-sfc": "3.3.4",
|
||||||
"autobind-decorator": "2.4.0",
|
"autobind-decorator": "2.4.0",
|
||||||
"autosize": "6.0.1",
|
"autosize": "6.0.1",
|
||||||
"blurhash": "2.0.5",
|
"blurhash": "2.0.5",
|
||||||
"broadcast-channel": "5.2.0",
|
"broadcast-channel": "5.3.0",
|
||||||
"browser-image-resizer": "github:misskey-dev/browser-image-resizer",
|
"browser-image-resizer": "github:misskey-dev/browser-image-resizer",
|
||||||
"chart.js": "4.3.3",
|
"chart.js": "4.4.0",
|
||||||
"chartjs-adapter-date-fns": "3.0.0",
|
"chartjs-adapter-date-fns": "3.0.0",
|
||||||
"chartjs-chart-matrix": "^2.0.1",
|
"chartjs-chart-matrix": "^2.0.1",
|
||||||
"chartjs-plugin-gradient": "0.6.1",
|
"chartjs-plugin-gradient": "0.6.1",
|
||||||
|
@ -63,36 +63,35 @@
|
||||||
"katex": "0.16.8",
|
"katex": "0.16.8",
|
||||||
"matter-js": "0.19.0",
|
"matter-js": "0.19.0",
|
||||||
"mfm-js": "0.23.3",
|
"mfm-js": "0.23.3",
|
||||||
"paralint": "^1.2.1",
|
|
||||||
"photoswipe": "5.3.8",
|
"photoswipe": "5.3.8",
|
||||||
"prettier": "3.0.2",
|
"prettier": "3.0.3",
|
||||||
"prettier-plugin-vue": "1.1.6",
|
"prettier-plugin-vue": "1.1.6",
|
||||||
"prismjs": "1.29.0",
|
"prismjs": "1.29.0",
|
||||||
"punycode": "2.3.0",
|
"punycode": "2.3.0",
|
||||||
"rndstr": "1.0.0",
|
"rndstr": "1.0.0",
|
||||||
"rollup": "3.28.0",
|
"rollup": "3.28.1",
|
||||||
"s-age": "1.1.2",
|
"s-age": "1.1.2",
|
||||||
"sass": "1.66.0",
|
"sass": "1.66.1",
|
||||||
"seedrandom": "3.0.5",
|
"seedrandom": "3.0.5",
|
||||||
"strict-event-emitter-types": "2.0.0",
|
"strict-event-emitter-types": "2.0.0",
|
||||||
"stringz": "2.1.0",
|
"stringz": "2.1.0",
|
||||||
"swiper": "10.2.0",
|
"swiper": "10.2.0",
|
||||||
"syuilo-password-strength": "0.0.1",
|
"syuilo-password-strength": "0.0.1",
|
||||||
"textarea-caret": "3.1.0",
|
"textarea-caret": "3.1.0",
|
||||||
"three": "0.155.0",
|
"three": "0.156.0",
|
||||||
"throttle-debounce": "5.0.0",
|
"throttle-debounce": "5.0.0",
|
||||||
"tinycolor2": "1.6.0",
|
"tinycolor2": "1.6.0",
|
||||||
"tsc-alias": "1.8.7",
|
"tsc-alias": "1.8.7",
|
||||||
"tsconfig-paths": "4.2.0",
|
"tsconfig-paths": "4.2.0",
|
||||||
"twemoji-parser": "14.0.0",
|
"twemoji-parser": "14.0.0",
|
||||||
"typescript": "5.1.6",
|
"typescript": "5.2.2",
|
||||||
"unicode-emoji-json": "^0.4.0",
|
"unicode-emoji-json": "^0.4.0",
|
||||||
"uuid": "9.0.0",
|
"uuid": "9.0.0",
|
||||||
"vanilla-tilt": "1.8.1",
|
"vanilla-tilt": "1.8.1",
|
||||||
"vite": "4.4.9",
|
"vite": "4.4.9",
|
||||||
"vite-plugin-compression": "^0.5.1",
|
"vite-plugin-compression": "^0.5.1",
|
||||||
"vue": "3.3.4",
|
"vue": "3.3.4",
|
||||||
"vue-draggable-plus": "^0.2.5",
|
"vue-draggable-plus": "^0.2.6",
|
||||||
"vue-isyourpasswordsafe": "^2.0.0",
|
"vue-isyourpasswordsafe": "^2.0.0",
|
||||||
"vue-plyr": "^7.0.0",
|
"vue-plyr": "^7.0.0",
|
||||||
"vue-prism-editor": "2.0.0-alpha.2"
|
"vue-prism-editor": "2.0.0-alpha.2"
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { defineAsyncComponent, reactive } from "vue";
|
import { defineAsyncComponent, reactive } from "vue";
|
||||||
import * as misskey from "firefish-js";
|
import type * as misskey from "firefish-js";
|
||||||
import { i18n } from "./i18n";
|
import { i18n } from "./i18n";
|
||||||
import { del, get, set } from "@/scripts/idb-proxy";
|
import { del, get, set } from "@/scripts/idb-proxy";
|
||||||
import { apiUrl } from "@/config";
|
import { apiUrl } from "@/config";
|
||||||
import { waiting, api, popup, popupMenu, success, alert } from "@/os";
|
import { alert, api, popup, popupMenu, success, waiting } from "@/os";
|
||||||
import { unisonReload, reloadChannel } from "@/scripts/unison-reload";
|
import { reloadChannel, unisonReload } from "@/scripts/unison-reload";
|
||||||
|
|
||||||
// TODO: 他のタブと永続化されたstateを同期
|
// TODO: 他のタブと永続化されたstateを同期
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ export async function signout() {
|
||||||
|
|
||||||
const accounts = await getAccounts();
|
const accounts = await getAccounts();
|
||||||
|
|
||||||
//#region Remove service worker registration
|
// #region Remove service worker registration
|
||||||
try {
|
try {
|
||||||
if (navigator.serviceWorker.controller) {
|
if (navigator.serviceWorker.controller) {
|
||||||
const registration = await navigator.serviceWorker.ready;
|
const registration = await navigator.serviceWorker.ready;
|
||||||
|
@ -52,7 +52,7 @@ export async function signout() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (err) {}
|
} catch (err) {}
|
||||||
//#endregion
|
// #endregion
|
||||||
|
|
||||||
document.cookie = "igi=; path=/";
|
document.cookie = "igi=; path=/";
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,11 @@
|
||||||
<div :class="$style.time">
|
<div :class="$style.time">
|
||||||
<MkTime :time="announcement.createdAt" />
|
<MkTime :time="announcement.createdAt" />
|
||||||
<div v-if="announcement.updatedAt">
|
<div v-if="announcement.updatedAt">
|
||||||
{{ i18n.ts.updatedAt }}:
|
<small>
|
||||||
<MkTime :time="announcement.createdAt" />
|
{{ i18n.ts.updatedAt }}:
|
||||||
</div>
|
<MkTime :time="announcement.createdAt" />
|
||||||
|
</small>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<Mfm :text="text" />
|
<Mfm :text="text" />
|
||||||
<img
|
<img
|
||||||
|
@ -80,6 +82,6 @@ const gotIt = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
.gotIt {
|
.gotIt {
|
||||||
margin: 8px 0 0 0;
|
margin: 1rem 0 1rem 2rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -199,7 +199,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onBeforeUnmount, onMounted, ref, shallowRef, computed } from "vue";
|
import { computed, onBeforeUnmount, onMounted, ref, shallowRef } from "vue";
|
||||||
import * as Acct from "firefish-js/built/acct";
|
import * as Acct from "firefish-js/built/acct";
|
||||||
import MkModal from "@/components/MkModal.vue";
|
import MkModal from "@/components/MkModal.vue";
|
||||||
import MkButton from "@/components/MkButton.vue";
|
import MkButton from "@/components/MkButton.vue";
|
||||||
|
@ -281,7 +281,9 @@ const modal = shallowRef<InstanceType<typeof MkModal>>();
|
||||||
const inputValue = ref<string | number | null>(props.input?.default ?? null);
|
const inputValue = ref<string | number | null>(props.input?.default ?? null);
|
||||||
const selectedValue = ref(props.select?.default ?? null);
|
const selectedValue = ref(props.select?.default ?? null);
|
||||||
|
|
||||||
let disabledReason = ref<null | "charactersExceeded" | "charactersBelow">(null);
|
const disabledReason = ref<null | "charactersExceeded" | "charactersBelow">(
|
||||||
|
null,
|
||||||
|
);
|
||||||
const okButtonDisabled = computed<boolean>(() => {
|
const okButtonDisabled = computed<boolean>(() => {
|
||||||
if (props.input) {
|
if (props.input) {
|
||||||
if (props.input.minLength) {
|
if (props.input.minLength) {
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, defineAsyncComponent, ref } from "vue";
|
import { computed, defineAsyncComponent, ref } from "vue";
|
||||||
import * as Misskey from "firefish-js";
|
import type * as Misskey from "firefish-js";
|
||||||
import copyToClipboard from "@/scripts/copy-to-clipboard";
|
import copyToClipboard from "@/scripts/copy-to-clipboard";
|
||||||
import MkDriveFileThumbnail from "@/components/MkDriveFileThumbnail.vue";
|
import MkDriveFileThumbnail from "@/components/MkDriveFileThumbnail.vue";
|
||||||
import bytes from "@/filters/bytes";
|
import bytes from "@/filters/bytes";
|
||||||
|
@ -160,7 +160,7 @@ function rename() {
|
||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
os.api("drive/files/update", {
|
os.api("drive/files/update", {
|
||||||
fileId: props.file.id,
|
fileId: props.file.id,
|
||||||
name: name,
|
name,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -179,7 +179,7 @@ function describe() {
|
||||||
{
|
{
|
||||||
done: (result) => {
|
done: (result) => {
|
||||||
if (!result || result.canceled) return;
|
if (!result || result.canceled) return;
|
||||||
let comment = result.result;
|
const comment = result.result;
|
||||||
os.api("drive/files/update", {
|
os.api("drive/files/update", {
|
||||||
fileId: props.file.id,
|
fileId: props.file.id,
|
||||||
comment: comment.length === 0 ? null : comment,
|
comment: comment.length === 0 ? null : comment,
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, defineAsyncComponent, ref } from "vue";
|
import { computed, defineAsyncComponent, ref } from "vue";
|
||||||
import * as Misskey from "firefish-js";
|
import type * as Misskey from "firefish-js";
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
import { defaultStore } from "@/store";
|
import { defaultStore } from "@/store";
|
||||||
|
@ -131,7 +131,7 @@ function onDrop(ev: DragEvent) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region ドライブのファイル
|
// #region ドライブのファイル
|
||||||
const driveFile = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_);
|
const driveFile = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_);
|
||||||
if (driveFile != null && driveFile !== "") {
|
if (driveFile != null && driveFile !== "") {
|
||||||
const file = JSON.parse(driveFile);
|
const file = JSON.parse(driveFile);
|
||||||
|
@ -141,9 +141,9 @@ function onDrop(ev: DragEvent) {
|
||||||
folderId: props.folder.id,
|
folderId: props.folder.id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//#endregion
|
// #endregion
|
||||||
|
|
||||||
//#region ドライブのフォルダ
|
// #region ドライブのフォルダ
|
||||||
const driveFolder = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FOLDER_);
|
const driveFolder = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FOLDER_);
|
||||||
if (driveFolder != null && driveFolder !== "") {
|
if (driveFolder != null && driveFolder !== "") {
|
||||||
const folder = JSON.parse(driveFolder);
|
const folder = JSON.parse(driveFolder);
|
||||||
|
@ -175,7 +175,7 @@ function onDrop(ev: DragEvent) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//#endregion
|
// #endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
function onDragstart(ev: DragEvent) {
|
function onDragstart(ev: DragEvent) {
|
||||||
|
@ -207,7 +207,7 @@ function rename() {
|
||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
os.api("drive/folders/update", {
|
os.api("drive/folders/update", {
|
||||||
folderId: props.folder.id,
|
folderId: props.folder.id,
|
||||||
name: name,
|
name,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import * as Misskey from "firefish-js";
|
import type * as Misskey from "firefish-js";
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ function onDrop(ev: DragEvent) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region ドライブのファイル
|
// #region ドライブのファイル
|
||||||
const driveFile = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_);
|
const driveFile = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_);
|
||||||
if (driveFile != null && driveFile !== "") {
|
if (driveFile != null && driveFile !== "") {
|
||||||
const file = JSON.parse(driveFile);
|
const file = JSON.parse(driveFile);
|
||||||
|
@ -96,9 +96,9 @@ function onDrop(ev: DragEvent) {
|
||||||
folderId: props.folder ? props.folder.id : null,
|
folderId: props.folder ? props.folder.id : null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//#endregion
|
// #endregion
|
||||||
|
|
||||||
//#region ドライブのフォルダ
|
// #region ドライブのフォルダ
|
||||||
const driveFolder = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FOLDER_);
|
const driveFolder = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FOLDER_);
|
||||||
if (driveFolder != null && driveFolder !== "") {
|
if (driveFolder != null && driveFolder !== "") {
|
||||||
const folder = JSON.parse(driveFolder);
|
const folder = JSON.parse(driveFolder);
|
||||||
|
@ -110,7 +110,7 @@ function onDrop(ev: DragEvent) {
|
||||||
parentId: props.folder ? props.folder.id : null,
|
parentId: props.folder ? props.folder.id : null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//#endregion
|
// #endregion
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -139,7 +139,7 @@ import {
|
||||||
ref,
|
ref,
|
||||||
watch,
|
watch,
|
||||||
} from "vue";
|
} from "vue";
|
||||||
import * as Misskey from "firefish-js";
|
import type * as Misskey from "firefish-js";
|
||||||
import MkButton from "./MkButton.vue";
|
import MkButton from "./MkButton.vue";
|
||||||
import XNavFolder from "@/components/MkDrive.navFolder.vue";
|
import XNavFolder from "@/components/MkDrive.navFolder.vue";
|
||||||
import XFolder from "@/components/MkDrive.folder.vue";
|
import XFolder from "@/components/MkDrive.folder.vue";
|
||||||
|
@ -294,7 +294,7 @@ function onDrop(ev: DragEvent): any {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region ドライブのファイル
|
// #region ドライブのファイル
|
||||||
const driveFile = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_);
|
const driveFile = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_);
|
||||||
if (driveFile != null && driveFile !== "") {
|
if (driveFile != null && driveFile !== "") {
|
||||||
const file = JSON.parse(driveFile);
|
const file = JSON.parse(driveFile);
|
||||||
|
@ -305,9 +305,9 @@ function onDrop(ev: DragEvent): any {
|
||||||
folderId: folder.value ? folder.value.id : null,
|
folderId: folder.value ? folder.value.id : null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//#endregion
|
// #endregion
|
||||||
|
|
||||||
//#region ドライブのフォルダ
|
// #region ドライブのフォルダ
|
||||||
const driveFolder = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FOLDER_);
|
const driveFolder = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FOLDER_);
|
||||||
if (driveFolder != null && driveFolder !== "") {
|
if (driveFolder != null && driveFolder !== "") {
|
||||||
const droppedFolder = JSON.parse(driveFolder);
|
const droppedFolder = JSON.parse(driveFolder);
|
||||||
|
@ -339,7 +339,7 @@ function onDrop(ev: DragEvent): any {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//#endregion
|
// #endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectLocalFile() {
|
function selectLocalFile() {
|
||||||
|
@ -354,7 +354,7 @@ function urlUpload() {
|
||||||
}).then(({ canceled, result: url }) => {
|
}).then(({ canceled, result: url }) => {
|
||||||
if (canceled || !url) return;
|
if (canceled || !url) return;
|
||||||
os.api("drive/files/upload-from-url", {
|
os.api("drive/files/upload-from-url", {
|
||||||
url: url,
|
url,
|
||||||
folderId: folder.value ? folder.value.id : undefined,
|
folderId: folder.value ? folder.value.id : undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -372,7 +372,7 @@ function createFolder() {
|
||||||
}).then(({ canceled, result: name }) => {
|
}).then(({ canceled, result: name }) => {
|
||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
os.api("drive/folders/create", {
|
os.api("drive/folders/create", {
|
||||||
name: name,
|
name,
|
||||||
parentId: folder.value ? folder.value.id : undefined,
|
parentId: folder.value ? folder.value.id : undefined,
|
||||||
}).then((createdFolder) => {
|
}).then((createdFolder) => {
|
||||||
addFolder(createdFolder, true);
|
addFolder(createdFolder, true);
|
||||||
|
@ -389,7 +389,7 @@ function renameFolder(folderToRename: Misskey.entities.DriveFolder) {
|
||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
os.api("drive/folders/update", {
|
os.api("drive/folders/update", {
|
||||||
folderId: folderToRename.id,
|
folderId: folderToRename.id,
|
||||||
name: name,
|
name,
|
||||||
}).then((updatedFolder) => {
|
}).then((updatedFolder) => {
|
||||||
// FIXME: 画面を更新するために自分自身に移動
|
// FIXME: 画面を更新するために自分自身に移動
|
||||||
move(updatedFolder);
|
move(updatedFolder);
|
||||||
|
|
|
@ -68,7 +68,7 @@ const is = computed(() => {
|
||||||
"application/x-tar",
|
"application/x-tar",
|
||||||
"application/gzip",
|
"application/gzip",
|
||||||
"application/x-7z-compressed",
|
"application/x-7z-compressed",
|
||||||
].some((archiveType) => archiveType === props.file.type)
|
].includes(props.file.type)
|
||||||
)
|
)
|
||||||
return "archive";
|
return "archive";
|
||||||
return "unknown";
|
return "unknown";
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import * as Misskey from "firefish-js";
|
import type * as Misskey from "firefish-js";
|
||||||
import XDrive from "@/components/MkDrive.vue";
|
import XDrive from "@/components/MkDrive.vue";
|
||||||
import XModalWindow from "@/components/MkModalWindow.vue";
|
import XModalWindow from "@/components/MkModalWindow.vue";
|
||||||
import number from "@/filters/number";
|
import number from "@/filters/number";
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {} from "vue";
|
import {} from "vue";
|
||||||
import * as Misskey from "firefish-js";
|
import type * as Misskey from "firefish-js";
|
||||||
import XDrive from "@/components/MkDrive.vue";
|
import XDrive from "@/components/MkDrive.vue";
|
||||||
import XWindow from "@/components/MkWindow.vue";
|
import XWindow from "@/components/MkWindow.vue";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, watch, onMounted } from "vue";
|
import { onMounted, ref, watch } from "vue";
|
||||||
import { addSkinTone } from "@/scripts/emojilist";
|
import { addSkinTone } from "@/scripts/emojilist";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<FocusTrap v-bind:active="isActive">
|
<FocusTrap :active="isActive">
|
||||||
<div
|
<div
|
||||||
class="omfetrab"
|
class="omfetrab"
|
||||||
:class="['s' + size, 'w' + width, 'h' + height, { asDrawer }]"
|
:class="['s' + size, 'w' + width, 'h' + height, { asDrawer }]"
|
||||||
|
@ -163,14 +163,15 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed, watch, onMounted } from "vue";
|
import { computed, onMounted, ref, watch } from "vue";
|
||||||
import * as Misskey from "firefish-js";
|
import type * as Misskey from "firefish-js";
|
||||||
|
import { FocusTrap } from "focus-trap-vue";
|
||||||
import XSection from "@/components/MkEmojiPicker.section.vue";
|
import XSection from "@/components/MkEmojiPicker.section.vue";
|
||||||
|
import type { UnicodeEmojiDef } from "@/scripts/emojilist";
|
||||||
import {
|
import {
|
||||||
emojilist,
|
emojilist,
|
||||||
unicodeEmojiCategories,
|
|
||||||
UnicodeEmojiDef,
|
|
||||||
getNicelyLabeledCategory,
|
getNicelyLabeledCategory,
|
||||||
|
unicodeEmojiCategories,
|
||||||
} from "@/scripts/emojilist";
|
} from "@/scripts/emojilist";
|
||||||
import { getStaticImageUrl } from "@/scripts/get-static-image-url";
|
import { getStaticImageUrl } from "@/scripts/get-static-image-url";
|
||||||
import Ripple from "@/components/MkRipple.vue";
|
import Ripple from "@/components/MkRipple.vue";
|
||||||
|
@ -180,7 +181,6 @@ import { deviceKind } from "@/scripts/device-kind";
|
||||||
import { emojiCategories, instance } from "@/instance";
|
import { emojiCategories, instance } from "@/instance";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
import { defaultStore } from "@/store";
|
import { defaultStore } from "@/store";
|
||||||
import { FocusTrap } from "focus-trap-vue";
|
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import * as Misskey from "firefish-js";
|
import type * as Misskey from "firefish-js";
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
|
|
||||||
const meta = ref<Misskey.entities.DetailedInstanceMetadata>();
|
const meta = ref<Misskey.entities.DetailedInstanceMetadata>();
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
<button
|
<button
|
||||||
v-if="!hideMenu"
|
v-if="!hideMenu"
|
||||||
|
v-tooltip="i18n.ts.menu"
|
||||||
class="menu _button"
|
class="menu _button"
|
||||||
@click.stop="menu"
|
@click.stop="menu"
|
||||||
v-tooltip="i18n.ts.menu"
|
|
||||||
>
|
>
|
||||||
<i class="ph-dots-three-outline ph-bold ph-lg"></i>
|
<i class="ph-dots-three-outline ph-bold ph-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="$i != null && $i.id != user.id"
|
v-if="$i != null && $i.id != user.id"
|
||||||
|
v-tooltip="full ? null : `${state} ${user.name || user.username}`"
|
||||||
class="kpoogebi _button follow-button"
|
class="kpoogebi _button follow-button"
|
||||||
:class="{
|
:class="{
|
||||||
wait,
|
wait,
|
||||||
|
@ -18,9 +19,8 @@
|
||||||
blocking: isBlocking,
|
blocking: isBlocking,
|
||||||
}"
|
}"
|
||||||
:disabled="wait"
|
:disabled="wait"
|
||||||
@click.stop="onClick"
|
|
||||||
:aria-label="`${state} ${user.name || user.username}`"
|
:aria-label="`${state} ${user.name || user.username}`"
|
||||||
v-tooltip="full ? null : `${state} ${user.name || user.username}`"
|
@click.stop="onClick"
|
||||||
>
|
>
|
||||||
<template v-if="!wait">
|
<template v-if="!wait">
|
||||||
<template v-if="isBlocking">
|
<template v-if="isBlocking">
|
||||||
|
@ -88,13 +88,13 @@ const props = withDefaults(
|
||||||
|
|
||||||
const isBlocking = computed(() => props.user.isBlocking);
|
const isBlocking = computed(() => props.user.isBlocking);
|
||||||
|
|
||||||
let state = ref(i18n.ts.processing);
|
const state = ref(i18n.ts.processing);
|
||||||
|
|
||||||
let isFollowing = ref(props.user.isFollowing);
|
const isFollowing = ref(props.user.isFollowing);
|
||||||
let hasPendingFollowRequestFromYou = ref(
|
const hasPendingFollowRequestFromYou = ref(
|
||||||
props.user.hasPendingFollowRequestFromYou,
|
props.user.hasPendingFollowRequestFromYou,
|
||||||
);
|
);
|
||||||
let wait = ref(false);
|
const wait = ref(false);
|
||||||
const connection = stream.useChannel("main");
|
const connection = stream.useChannel("main");
|
||||||
|
|
||||||
if (props.user.isFollowing == null) {
|
if (props.user.isFollowing == null) {
|
||||||
|
|
|
@ -64,7 +64,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
|
|
||||||
import {} from "vue";
|
|
||||||
import XModalWindow from "@/components/MkModalWindow.vue";
|
import XModalWindow from "@/components/MkModalWindow.vue";
|
||||||
import MkButton from "@/components/MkButton.vue";
|
import MkButton from "@/components/MkButton.vue";
|
||||||
import MkInput from "@/components/form/input.vue";
|
import MkInput from "@/components/form/input.vue";
|
||||||
|
@ -77,11 +76,11 @@ const emit = defineEmits<{
|
||||||
(ev: "closed"): void;
|
(ev: "closed"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let dialog: InstanceType<typeof XModalWindow> = ref();
|
const dialog: InstanceType<typeof XModalWindow> = ref();
|
||||||
|
|
||||||
let username = ref("");
|
const username = ref("");
|
||||||
let email = ref("");
|
const email = ref("");
|
||||||
let processing = ref(false);
|
const processing = ref(false);
|
||||||
|
|
||||||
async function onSubmit() {
|
async function onSubmit() {
|
||||||
processing.value = true;
|
processing.value = true;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, defineAsyncComponent } from "vue";
|
import { defineAsyncComponent, defineComponent } from "vue";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, nextTick, watch, shallowRef, ref } from "vue";
|
import { nextTick, onMounted, ref, shallowRef, watch } from "vue";
|
||||||
import { Chart } from "chart.js";
|
import { Chart } from "chart.js";
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
import { defaultStore } from "@/store";
|
import { defaultStore } from "@/store";
|
||||||
|
@ -26,8 +26,8 @@ const props = defineProps<{
|
||||||
const rootEl = shallowRef<HTMLDivElement>(null);
|
const rootEl = shallowRef<HTMLDivElement>(null);
|
||||||
const chartEl = shallowRef<HTMLCanvasElement>(null);
|
const chartEl = shallowRef<HTMLCanvasElement>(null);
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
let chartInstance: Chart = null;
|
let chartInstance: Chart = null,
|
||||||
let fetching = ref(true);
|
fetching = ref(true);
|
||||||
|
|
||||||
const { handler: externalTooltipHandler } = useChartTooltip({
|
const { handler: externalTooltipHandler } = useChartTooltip({
|
||||||
position: "middle",
|
position: "middle",
|
||||||
|
@ -233,7 +233,7 @@ async function renderChart() {
|
||||||
return ["Active: " + v.v];
|
return ["Active: " + v.v];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
//mode: 'index',
|
// mode: 'index',
|
||||||
animation: {
|
animation: {
|
||||||
duration: 0,
|
duration: 0,
|
||||||
},
|
},
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
|
|
||||||
import {} from "vue";
|
|
||||||
import type * as misskey from "firefish-js";
|
import type * as misskey from "firefish-js";
|
||||||
import bytes from "@/filters/bytes";
|
import bytes from "@/filters/bytes";
|
||||||
import number from "@/filters/number";
|
import number from "@/filters/number";
|
||||||
|
|
|
@ -49,7 +49,7 @@ const props = withDefaults(
|
||||||
);
|
);
|
||||||
|
|
||||||
const canvas = ref<HTMLCanvasElement>();
|
const canvas = ref<HTMLCanvasElement>();
|
||||||
let loaded = ref(false);
|
const loaded = ref(false);
|
||||||
|
|
||||||
function draw() {
|
function draw() {
|
||||||
if (props.hash == null || canvas.value == null) return;
|
if (props.hash == null || canvas.value == null) return;
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
v-if="closeable"
|
v-if="closeable"
|
||||||
v-tooltip="i18n.ts.close"
|
v-tooltip="i18n.ts.close"
|
||||||
class="_buttonIcon close"
|
class="_buttonIcon close"
|
||||||
@click.stop="close"
|
|
||||||
:aria-label="i18n.t('close')"
|
:aria-label="i18n.t('close')"
|
||||||
|
@click.stop="close"
|
||||||
>
|
>
|
||||||
<i class="ph-x ph-bold ph-lg"></i>
|
<i class="ph-x ph-bold ph-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
|
|
||||||
import * as firefish from "firefish-js";
|
import type * as firefish from "firefish-js";
|
||||||
import MkMiniChart from "@/components/MkMiniChart.vue";
|
import MkMiniChart from "@/components/MkMiniChart.vue";
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
import { getProxiedImageUrlNullable } from "@/scripts/media-proxy";
|
import { getProxiedImageUrlNullable } from "@/scripts/media-proxy";
|
||||||
|
@ -35,7 +35,7 @@ const props = defineProps<{
|
||||||
instance: firefish.entities.Instance;
|
instance: firefish.entities.Instance;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let chartValues = ref<number[] | null>(null);
|
const chartValues = ref<number[] | null>(null);
|
||||||
|
|
||||||
os.apiGet("charts/instance", {
|
os.apiGet("charts/instance", {
|
||||||
host: props.instance.host,
|
host: props.instance.host,
|
||||||
|
|
|
@ -58,11 +58,11 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
|
|
||||||
|
import type { Instance } from "firefish-js/built/entities";
|
||||||
import MkInput from "@/components/form/input.vue";
|
import MkInput from "@/components/form/input.vue";
|
||||||
import XModalWindow from "@/components/MkModalWindow.vue";
|
import XModalWindow from "@/components/MkModalWindow.vue";
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
import { Instance } from "firefish-js/built/entities";
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: "ok", selected: Instance): void;
|
(ev: "ok", selected: Instance): void;
|
||||||
|
@ -70,10 +70,10 @@ const emit = defineEmits<{
|
||||||
(ev: "closed"): void;
|
(ev: "closed"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let hostname = ref("");
|
const hostname = ref("");
|
||||||
let instances: Instance[] = ref([]);
|
const instances: Instance[] = ref([]);
|
||||||
let selected: Instance | null = ref(null);
|
const selected: Instance | null = ref(null);
|
||||||
let dialogEl = ref<InstanceType<typeof XModalWindow>>();
|
const dialogEl = ref<InstanceType<typeof XModalWindow>>();
|
||||||
|
|
||||||
let searchOrderLatch = 0;
|
let searchOrderLatch = 0;
|
||||||
const search = () => {
|
const search = () => {
|
||||||
|
|
|
@ -116,11 +116,11 @@ import { initChart } from "@/scripts/init-chart";
|
||||||
initChart();
|
initChart();
|
||||||
|
|
||||||
const chartLimit = 500;
|
const chartLimit = 500;
|
||||||
let chartSpan = ref<"hour" | "day">("hour");
|
const chartSpan = ref<"hour" | "day">("hour");
|
||||||
let chartSrc = ref("active-users");
|
const chartSrc = ref("active-users");
|
||||||
let heatmapSrc = ref("active-users");
|
const heatmapSrc = ref("active-users");
|
||||||
let subDoughnutEl = shallowRef<HTMLCanvasElement>();
|
const subDoughnutEl = shallowRef<HTMLCanvasElement>();
|
||||||
let pubDoughnutEl = shallowRef<HTMLCanvasElement>();
|
const pubDoughnutEl = shallowRef<HTMLCanvasElement>();
|
||||||
|
|
||||||
const { handler: externalTooltipHandler1 } = useChartTooltip({
|
const { handler: externalTooltipHandler1 } = useChartTooltip({
|
||||||
position: "middle",
|
position: "middle",
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="hpaizdrt"
|
|
||||||
v-tooltip="capitalize(instance.softwareName)"
|
|
||||||
ref="ticker"
|
ref="ticker"
|
||||||
|
v-tooltip="capitalize(instance.softwareName)"
|
||||||
|
class="hpaizdrt"
|
||||||
:style="bg"
|
:style="bg"
|
||||||
>
|
>
|
||||||
<img class="icon" :src="getInstanceIcon(instance)" aria-hidden="true" />
|
<img class="icon" :src="getInstanceIcon(instance)" aria-hidden="true" />
|
||||||
|
@ -26,7 +26,7 @@ const props = defineProps<{
|
||||||
};
|
};
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let ticker = ref<HTMLElement | null>(null);
|
const ticker = ref<HTMLElement | null>(null);
|
||||||
|
|
||||||
// if no instance data is given, this is for the local instance
|
// if no instance data is given, this is for the local instance
|
||||||
const instance = props.instance ?? {
|
const instance = props.instance ?? {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="media" v-size="{ max: [350] }">
|
<div v-size="{ max: [350] }" class="media">
|
||||||
<button v-if="hide" class="hidden" @click="hide = false">
|
<button v-if="hide" class="hidden" @click="hide = false">
|
||||||
<ImgWithBlurhash
|
<ImgWithBlurhash
|
||||||
:hash="media.blurhash"
|
:hash="media.blurhash"
|
||||||
|
@ -89,7 +89,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { watch, ref, computed } from "vue";
|
import { computed, ref, watch } from "vue";
|
||||||
import VuePlyr from "vue-plyr";
|
import VuePlyr from "vue-plyr";
|
||||||
import "vue-plyr/dist/vue-plyr.css";
|
import "vue-plyr/dist/vue-plyr.css";
|
||||||
import type * as misskey from "firefish-js";
|
import type * as misskey from "firefish-js";
|
||||||
|
@ -104,7 +104,7 @@ const props = defineProps<{
|
||||||
raw?: boolean;
|
raw?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let hide = ref(true);
|
const hide = ref(true);
|
||||||
|
|
||||||
const plyr = ref();
|
const plyr = ref();
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ const props = withDefaults(
|
||||||
);
|
);
|
||||||
|
|
||||||
const audioEl = ref<HTMLAudioElement | null>();
|
const audioEl = ref<HTMLAudioElement | null>();
|
||||||
let hide = ref(true);
|
const hide = ref(true);
|
||||||
|
|
||||||
function volumechange() {
|
function volumechange() {
|
||||||
if (audioEl.value)
|
if (audioEl.value)
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from "vue";
|
import { onMounted, ref } from "vue";
|
||||||
import * as misskey from "firefish-js";
|
import type * as misskey from "firefish-js";
|
||||||
import PhotoSwipeLightbox from "photoswipe/lightbox";
|
import PhotoSwipeLightbox from "photoswipe/lightbox";
|
||||||
import PhotoSwipe from "photoswipe";
|
import PhotoSwipe from "photoswipe";
|
||||||
import "photoswipe/style.css";
|
import "photoswipe/style.css";
|
||||||
|
@ -125,11 +125,11 @@ onMounted(() => {
|
||||||
className: "pwsp__alt-text-container",
|
className: "pwsp__alt-text-container",
|
||||||
appendTo: "wrapper",
|
appendTo: "wrapper",
|
||||||
onInit: (el, pwsp) => {
|
onInit: (el, pwsp) => {
|
||||||
let textBox = document.createElement("p");
|
const textBox = document.createElement("p");
|
||||||
textBox.className = "pwsp__alt-text";
|
textBox.className = "pwsp__alt-text";
|
||||||
el.appendChild(textBox);
|
el.appendChild(textBox);
|
||||||
|
|
||||||
let preventProp = function (ev: Event): void {
|
const preventProp = function (ev: Event): void {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { nextTick, onMounted, ref } from "vue";
|
import { nextTick, onMounted, ref } from "vue";
|
||||||
import MkMenu from "./MkMenu.vue";
|
import MkMenu from "./MkMenu.vue";
|
||||||
import { MenuItem } from "@/types/menu";
|
import type { MenuItem } from "@/types/menu";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
items: MenuItem[];
|
items: MenuItem[];
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
width: width && !asDrawer ? width + 'px' : '',
|
width: width && !asDrawer ? width + 'px' : '',
|
||||||
maxHeight: maxHeight ? maxHeight + 'px' : '',
|
maxHeight: maxHeight ? maxHeight + 'px' : '',
|
||||||
}"
|
}"
|
||||||
@contextmenu.self="(e) => e.preventDefault()"
|
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
|
@contextmenu.self="(e) => e.preventDefault()"
|
||||||
>
|
>
|
||||||
<template v-for="item in items2">
|
<template v-for="item in items2">
|
||||||
<div v-if="item === null" class="divider"></div>
|
<div v-if="item === null" class="divider"></div>
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
v-if="item.avatar"
|
v-if="item.avatar"
|
||||||
:user="item.avatar"
|
:user="item.avatar"
|
||||||
class="avatar"
|
class="avatar"
|
||||||
disableLink
|
disable-link
|
||||||
/>
|
/>
|
||||||
<span :style="item.textStyle || ''">{{
|
<span :style="item.textStyle || ''">{{
|
||||||
item.text
|
item.text
|
||||||
|
@ -100,7 +100,7 @@
|
||||||
<MkAvatar
|
<MkAvatar
|
||||||
:user="item.user"
|
:user="item.user"
|
||||||
class="avatar"
|
class="avatar"
|
||||||
disableLink
|
disable-link
|
||||||
/><MkUserName :user="item.user" />
|
/><MkUserName :user="item.user" />
|
||||||
<span
|
<span
|
||||||
v-if="item.indicate"
|
v-if="item.indicate"
|
||||||
|
@ -168,7 +168,7 @@
|
||||||
v-if="item.avatar"
|
v-if="item.avatar"
|
||||||
:user="item.avatar"
|
:user="item.avatar"
|
||||||
class="avatar"
|
class="avatar"
|
||||||
disableLink
|
disable-link
|
||||||
/>
|
/>
|
||||||
<span :style="item.textStyle || ''">{{
|
<span :style="item.textStyle || ''">{{
|
||||||
item.text
|
item.text
|
||||||
|
@ -210,11 +210,16 @@ import {
|
||||||
ref,
|
ref,
|
||||||
watch,
|
watch,
|
||||||
} from "vue";
|
} from "vue";
|
||||||
|
import { FocusTrap } from "focus-trap-vue";
|
||||||
import FormSwitch from "@/components/form/switch.vue";
|
import FormSwitch from "@/components/form/switch.vue";
|
||||||
import { MenuItem, InnerMenuItem, MenuPending, MenuAction } from "@/types/menu";
|
import type {
|
||||||
|
InnerMenuItem,
|
||||||
|
MenuAction,
|
||||||
|
MenuItem,
|
||||||
|
MenuPending,
|
||||||
|
} from "@/types/menu";
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
import { FocusTrap } from "focus-trap-vue";
|
|
||||||
|
|
||||||
const XChild = defineAsyncComponent(() => import("./MkMenu.child.vue"));
|
const XChild = defineAsyncComponent(() => import("./MkMenu.child.vue"));
|
||||||
const focusTrap = ref();
|
const focusTrap = ref();
|
||||||
|
@ -233,13 +238,13 @@ const emit = defineEmits<{
|
||||||
(ev: "close", actioned?: boolean): void;
|
(ev: "close", actioned?: boolean): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let itemsEl = ref<HTMLDivElement>();
|
const itemsEl = ref<HTMLDivElement>();
|
||||||
|
|
||||||
let items2: InnerMenuItem[] = ref([]);
|
const items2: InnerMenuItem[] = ref([]);
|
||||||
|
|
||||||
let child = ref<InstanceType<typeof XChild>>();
|
const child = ref<InstanceType<typeof XChild>>();
|
||||||
|
|
||||||
let childShowingItem = ref<MenuItem | null>();
|
const childShowingItem = ref<MenuItem | null>();
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.items,
|
() => props.items,
|
||||||
|
@ -267,8 +272,8 @@ watch(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let childMenu = ref<MenuItem[] | null>();
|
const childMenu = ref<MenuItem[] | null>();
|
||||||
let childTarget = ref<HTMLElement | null>();
|
const childTarget = ref<HTMLElement | null>();
|
||||||
|
|
||||||
function closeChild() {
|
function closeChild() {
|
||||||
childMenu.value = null;
|
childMenu.value = null;
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { watch, ref } from "vue";
|
import { ref, watch } from "vue";
|
||||||
import { v4 as uuid } from "uuid";
|
import { v4 as uuid } from "uuid";
|
||||||
import tinycolor from "tinycolor2";
|
import tinycolor from "tinycolor2";
|
||||||
import { useInterval } from "@/scripts/use-interval";
|
import { useInterval } from "@/scripts/use-interval";
|
||||||
|
@ -37,10 +37,10 @@ const props = defineProps<{
|
||||||
const viewBoxX = 50;
|
const viewBoxX = 50;
|
||||||
const viewBoxY = 50;
|
const viewBoxY = 50;
|
||||||
const gradientId = uuid();
|
const gradientId = uuid();
|
||||||
let polylinePoints = ref("");
|
const polylinePoints = ref("");
|
||||||
let polygonPoints = ref("");
|
const polygonPoints = ref("");
|
||||||
let headX = ref<number | null>(null);
|
const headX = ref<number | null>(null);
|
||||||
let headY = ref<number | null>(null);
|
const headY = ref<number | null>(null);
|
||||||
const accent = tinycolor(
|
const accent = tinycolor(
|
||||||
getComputedStyle(document.documentElement).getPropertyValue("--accent"),
|
getComputedStyle(document.documentElement).getPropertyValue("--accent"),
|
||||||
);
|
);
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
<div
|
<div
|
||||||
v-show="manualShowing != null ? manualShowing : showing"
|
v-show="manualShowing != null ? manualShowing : showing"
|
||||||
v-hotkey.global="keymap"
|
v-hotkey.global="keymap"
|
||||||
|
v-focus
|
||||||
:class="[
|
:class="[
|
||||||
$style.root,
|
$style.root,
|
||||||
{
|
{
|
||||||
|
@ -44,7 +45,6 @@
|
||||||
'--transformOrigin': transformOrigin,
|
'--transformOrigin': transformOrigin,
|
||||||
}"
|
}"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
v-focus
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="_modalBg data-cy-bg"
|
class="_modalBg data-cy-bg"
|
||||||
|
@ -78,20 +78,20 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {
|
import {
|
||||||
|
computed,
|
||||||
nextTick,
|
nextTick,
|
||||||
onMounted,
|
onMounted,
|
||||||
watch,
|
|
||||||
provide,
|
|
||||||
onUnmounted,
|
onUnmounted,
|
||||||
|
provide,
|
||||||
ref,
|
ref,
|
||||||
shallowRef,
|
shallowRef,
|
||||||
computed,
|
watch,
|
||||||
} from "vue";
|
} from "vue";
|
||||||
|
import { FocusTrap } from "focus-trap-vue";
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
import { isTouchUsing } from "@/scripts/touch";
|
import { isTouchUsing } from "@/scripts/touch";
|
||||||
import { defaultStore } from "@/store";
|
import { defaultStore } from "@/store";
|
||||||
import { deviceKind } from "@/scripts/device-kind";
|
import { deviceKind } from "@/scripts/device-kind";
|
||||||
import { FocusTrap } from "focus-trap-vue";
|
|
||||||
|
|
||||||
function getFixedContainer(el: Element | null): Element | null {
|
function getFixedContainer(el: Element | null): Element | null {
|
||||||
if (el == null || el.tagName === "BODY") return null;
|
if (el == null || el.tagName === "BODY") return null;
|
||||||
|
@ -139,13 +139,13 @@ const emit = defineEmits<{
|
||||||
|
|
||||||
provide("modal", true);
|
provide("modal", true);
|
||||||
|
|
||||||
let maxHeight = ref<number>();
|
const maxHeight = ref<number>();
|
||||||
let fixed = ref(false);
|
const fixed = ref(false);
|
||||||
let transformOrigin = ref("center");
|
const transformOrigin = ref("center");
|
||||||
let showing = ref(true);
|
const showing = ref(true);
|
||||||
let content = shallowRef<HTMLElement>();
|
const content = shallowRef<HTMLElement>();
|
||||||
const zIndex = os.claimZIndex(props.zPriority);
|
const zIndex = os.claimZIndex(props.zPriority);
|
||||||
let useSendAnime = ref(false);
|
const useSendAnime = ref(false);
|
||||||
const type = computed<ModalTypes>(() => {
|
const type = computed<ModalTypes>(() => {
|
||||||
if (props.preferType === "auto") {
|
if (props.preferType === "auto") {
|
||||||
if (
|
if (
|
||||||
|
@ -164,7 +164,7 @@ const type = computed<ModalTypes>(() => {
|
||||||
const isEnableBgTransparent = computed(
|
const isEnableBgTransparent = computed(
|
||||||
() => props.transparentBg && type.value === "popup",
|
() => props.transparentBg && type.value === "popup",
|
||||||
);
|
);
|
||||||
let transitionName = computed(() =>
|
const transitionName = computed(() =>
|
||||||
defaultStore.state.animation
|
defaultStore.state.animation
|
||||||
? useSendAnime.value
|
? useSendAnime.value
|
||||||
? "send"
|
? "send"
|
||||||
|
@ -175,7 +175,7 @@ let transitionName = computed(() =>
|
||||||
: "modal"
|
: "modal"
|
||||||
: "",
|
: "",
|
||||||
);
|
);
|
||||||
let transitionDuration = computed(() =>
|
const transitionDuration = computed(() =>
|
||||||
transitionName.value === "send"
|
transitionName.value === "send"
|
||||||
? 400
|
? 400
|
||||||
: transitionName.value === "modal-popup"
|
: transitionName.value === "modal-popup"
|
||||||
|
@ -235,8 +235,7 @@ const align = () => {
|
||||||
const width = content.value!.offsetWidth;
|
const width = content.value!.offsetWidth;
|
||||||
const height = content.value!.offsetHeight;
|
const height = content.value!.offsetHeight;
|
||||||
|
|
||||||
let left;
|
let left, top;
|
||||||
let top;
|
|
||||||
|
|
||||||
const x = srcRect.left + (fixed.value ? 0 : window.pageXOffset);
|
const x = srcRect.left + (fixed.value ? 0 : window.pageXOffset);
|
||||||
const y = srcRect.top + (fixed.value ? 0 : window.pageYOffset);
|
const y = srcRect.top + (fixed.value ? 0 : window.pageYOffset);
|
||||||
|
@ -321,8 +320,8 @@ const align = () => {
|
||||||
left = 0;
|
left = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let transformOriginX = "center";
|
let transformOriginX = "center",
|
||||||
let transformOriginY = "center";
|
transformOriginY = "center";
|
||||||
|
|
||||||
if (
|
if (
|
||||||
top >=
|
top >=
|
||||||
|
|
|
@ -28,8 +28,8 @@
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
class="_button"
|
class="_button"
|
||||||
@click="$refs.modal.close()"
|
|
||||||
:aria-label="i18n.t('close')"
|
:aria-label="i18n.t('close')"
|
||||||
|
@click="$refs.modal.close()"
|
||||||
>
|
>
|
||||||
<i class="ph-x ph-bold ph-lg"></i>
|
<i class="ph-x ph-bold ph-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
|
@ -52,7 +52,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ComputedRef, provide, ref, computed } from "vue";
|
import type { ComputedRef } from "vue";
|
||||||
|
import { computed, provide, ref } from "vue";
|
||||||
import MkModal from "@/components/MkModal.vue";
|
import MkModal from "@/components/MkModal.vue";
|
||||||
import { popout as _popout } from "@/scripts/popout";
|
import { popout as _popout } from "@/scripts/popout";
|
||||||
import copyToClipboard from "@/scripts/copy-to-clipboard";
|
import copyToClipboard from "@/scripts/copy-to-clipboard";
|
||||||
|
@ -60,7 +61,8 @@ import { url } from "@/config";
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
import { mainRouter, routes } from "@/router";
|
import { mainRouter, routes } from "@/router";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
import { PageMetadata, provideMetadataReceiver } from "@/scripts/page-metadata";
|
import type { PageMetadata } from "@/scripts/page-metadata";
|
||||||
|
import { provideMetadataReceiver } from "@/scripts/page-metadata";
|
||||||
import { Router } from "@/nirax";
|
import { Router } from "@/nirax";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
@ -76,12 +78,12 @@ const router = new Router(routes, props.initialPath);
|
||||||
|
|
||||||
router.addListener("push", (ctx) => {});
|
router.addListener("push", (ctx) => {});
|
||||||
|
|
||||||
let pageMetadata = ref<null | ComputedRef<PageMetadata>>();
|
const pageMetadata = ref<null | ComputedRef<PageMetadata>>();
|
||||||
let rootEl = ref();
|
const rootEl = ref();
|
||||||
let modal = ref<InstanceType<typeof MkModal>>();
|
const modal = ref<InstanceType<typeof MkModal>>();
|
||||||
let path = ref(props.initialPath);
|
const path = ref(props.initialPath);
|
||||||
let width = ref(860);
|
const width = ref(860);
|
||||||
let height = ref(660);
|
const height = ref(660);
|
||||||
const history = [];
|
const history = [];
|
||||||
|
|
||||||
provide("router", router);
|
provide("router", router);
|
||||||
|
|
|
@ -25,10 +25,10 @@
|
||||||
<div ref="headerEl" class="header">
|
<div ref="headerEl" class="header">
|
||||||
<button
|
<button
|
||||||
v-if="props.withOkButton"
|
v-if="props.withOkButton"
|
||||||
|
v-tooltip="i18n.ts.close"
|
||||||
:aria-label="i18n.t('close')"
|
:aria-label="i18n.t('close')"
|
||||||
class="_button"
|
class="_button"
|
||||||
@click="$emit('close')"
|
@click="$emit('close')"
|
||||||
v-tooltip="i18n.ts.close"
|
|
||||||
>
|
>
|
||||||
<i class="ph-x ph-bold ph-lg"></i>
|
<i class="ph-x ph-bold ph-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
|
@ -92,9 +92,9 @@ const emit = defineEmits<{
|
||||||
(event: "ok"): void;
|
(event: "ok"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let modal = shallowRef<InstanceType<typeof MkModal>>();
|
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
||||||
let rootEl = shallowRef<HTMLElement>();
|
const rootEl = shallowRef<HTMLElement>();
|
||||||
let headerEl = shallowRef<HTMLElement>();
|
const headerEl = shallowRef<HTMLElement>();
|
||||||
|
|
||||||
const close = (ev) => {
|
const close = (ev) => {
|
||||||
modal.value?.close(ev);
|
modal.value?.close(ev);
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
:aria-label="accessibleLabel"
|
|
||||||
v-if="!muted.muted"
|
v-if="!muted.muted"
|
||||||
v-show="!isDeleted"
|
v-show="!isDeleted"
|
||||||
|
:id="appearNote.id"
|
||||||
ref="el"
|
ref="el"
|
||||||
v-hotkey="keymap"
|
v-hotkey="keymap"
|
||||||
v-size="{ max: [500, 350] }"
|
v-size="{ max: [500, 350] }"
|
||||||
|
:aria-label="accessibleLabel"
|
||||||
class="tkcbzcuz note-container"
|
class="tkcbzcuz note-container"
|
||||||
:tabindex="!isDeleted ? '-1' : null"
|
:tabindex="!isDeleted ? '-1' : null"
|
||||||
:class="{ renote: isRenote }"
|
:class="{ renote: isRenote }"
|
||||||
:id="appearNote.id"
|
|
||||||
>
|
>
|
||||||
<MkNoteSub
|
<MkNoteSub
|
||||||
v-if="appearNote.reply && !detailedView && !collapsedReply"
|
v-if="appearNote.reply && !detailedView && !collapsedReply"
|
||||||
|
@ -19,10 +19,10 @@
|
||||||
<div
|
<div
|
||||||
v-if="!detailedView"
|
v-if="!detailedView"
|
||||||
class="note-context"
|
class="note-context"
|
||||||
@click="noteClick"
|
|
||||||
:class="{
|
:class="{
|
||||||
collapsedReply: collapsedReply && appearNote.reply,
|
collapsedReply: collapsedReply && appearNote.reply,
|
||||||
}"
|
}"
|
||||||
|
@click="noteClick"
|
||||||
>
|
>
|
||||||
<div class="line"></div>
|
<div class="line"></div>
|
||||||
<div v-if="appearNote._prId_" class="info">
|
<div v-if="appearNote._prId_" class="info">
|
||||||
|
@ -87,11 +87,11 @@
|
||||||
</div>
|
</div>
|
||||||
<article
|
<article
|
||||||
class="article"
|
class="article"
|
||||||
@contextmenu.stop="onContextmenu"
|
|
||||||
@click="noteClick"
|
|
||||||
:style="{
|
:style="{
|
||||||
cursor: expandOnNoteClick && !detailedView ? 'pointer' : '',
|
cursor: expandOnNoteClick && !detailedView ? 'pointer' : '',
|
||||||
}"
|
}"
|
||||||
|
@contextmenu.stop="onContextmenu"
|
||||||
|
@click="noteClick"
|
||||||
>
|
>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<div class="header-container">
|
<div class="header-container">
|
||||||
|
@ -103,8 +103,8 @@
|
||||||
class="text"
|
class="text"
|
||||||
:note="appearNote"
|
:note="appearNote"
|
||||||
:detailed="true"
|
:detailed="true"
|
||||||
:detailedView="detailedView"
|
:detailed-view="detailedView"
|
||||||
:parentId="appearNote.parentId"
|
:parent-id="appearNote.parentId"
|
||||||
@push="(e) => router.push(notePage(e))"
|
@push="(e) => router.push(notePage(e))"
|
||||||
@focusfooter="footerEl.focus()"
|
@focusfooter="footerEl.focus()"
|
||||||
@expanded="(e) => setPostExpanded(e)"
|
@expanded="(e) => setPostExpanded(e)"
|
||||||
|
@ -171,7 +171,7 @@
|
||||||
class="button"
|
class="button"
|
||||||
:note="appearNote"
|
:note="appearNote"
|
||||||
:count="appearNote.renoteCount"
|
:count="appearNote.renoteCount"
|
||||||
:detailedView="detailedView"
|
:detailed-view="detailedView"
|
||||||
/>
|
/>
|
||||||
<XStarButtonNoEmoji
|
<XStarButtonNoEmoji
|
||||||
v-if="!enableEmojiReactions"
|
v-if="!enableEmojiReactions"
|
||||||
|
@ -212,9 +212,9 @@
|
||||||
appearNote.myReaction != null
|
appearNote.myReaction != null
|
||||||
"
|
"
|
||||||
ref="reactButton"
|
ref="reactButton"
|
||||||
|
v-tooltip.noDelay.bottom="i18n.ts.removeReaction"
|
||||||
class="button _button reacted"
|
class="button _button reacted"
|
||||||
@click.stop="undoReact(appearNote)"
|
@click.stop="undoReact(appearNote)"
|
||||||
v-tooltip.noDelay.bottom="i18n.ts.removeReaction"
|
|
||||||
>
|
>
|
||||||
<i class="ph-minus ph-bold ph-lg"></i>
|
<i class="ph-minus ph-bold ph-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
|
@ -259,8 +259,8 @@ import { computed, inject, onMounted, ref } from "vue";
|
||||||
import * as mfm from "mfm-js";
|
import * as mfm from "mfm-js";
|
||||||
import type { Ref } from "vue";
|
import type { Ref } from "vue";
|
||||||
import type * as misskey from "firefish-js";
|
import type * as misskey from "firefish-js";
|
||||||
import MkNoteSub from "@/components/MkNoteSub.vue";
|
|
||||||
import MkSubNoteContent from "./MkSubNoteContent.vue";
|
import MkSubNoteContent from "./MkSubNoteContent.vue";
|
||||||
|
import MkNoteSub from "@/components/MkNoteSub.vue";
|
||||||
import XNoteHeader from "@/components/MkNoteHeader.vue";
|
import XNoteHeader from "@/components/MkNoteHeader.vue";
|
||||||
import XRenoteButton from "@/components/MkRenoteButton.vue";
|
import XRenoteButton from "@/components/MkRenoteButton.vue";
|
||||||
import XReactionsViewer from "@/components/MkReactionsViewer.vue";
|
import XReactionsViewer from "@/components/MkReactionsViewer.vue";
|
||||||
|
@ -271,7 +271,7 @@ import MkVisibility from "@/components/MkVisibility.vue";
|
||||||
import copyToClipboard from "@/scripts/copy-to-clipboard";
|
import copyToClipboard from "@/scripts/copy-to-clipboard";
|
||||||
import { url } from "@/config";
|
import { url } from "@/config";
|
||||||
import { pleaseLogin } from "@/scripts/please-login";
|
import { pleaseLogin } from "@/scripts/please-login";
|
||||||
import { focusPrev, focusNext } from "@/scripts/focus";
|
import { focusNext, focusPrev } from "@/scripts/focus";
|
||||||
import { getWordSoftMute } from "@/scripts/check-word-mute";
|
import { getWordSoftMute } from "@/scripts/check-word-mute";
|
||||||
import { useRouter } from "@/router";
|
import { useRouter } from "@/router";
|
||||||
import { userPage } from "@/filters/user";
|
import { userPage } from "@/filters/user";
|
||||||
|
@ -297,7 +297,7 @@ const props = defineProps<{
|
||||||
|
|
||||||
const inChannel = inject("inChannel", null);
|
const inChannel = inject("inChannel", null);
|
||||||
|
|
||||||
let note = ref(deepClone(props.note));
|
const note = ref(deepClone(props.note));
|
||||||
|
|
||||||
const softMuteReasonI18nSrc = (what?: string) => {
|
const softMuteReasonI18nSrc = (what?: string) => {
|
||||||
if (what === "note") return i18n.ts.userSaysSomethingReason;
|
if (what === "note") return i18n.ts.userSaysSomethingReason;
|
||||||
|
@ -333,7 +333,7 @@ const starButton = ref<InstanceType<typeof XStarButton>>();
|
||||||
const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
|
const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
|
||||||
const renoteTime = ref<HTMLElement>();
|
const renoteTime = ref<HTMLElement>();
|
||||||
const reactButton = ref<HTMLElement>();
|
const reactButton = ref<HTMLElement>();
|
||||||
let appearNote = computed(() =>
|
const appearNote = computed(() =>
|
||||||
isRenote ? (note.value.renote as misskey.entities.Note) : note.value,
|
isRenote ? (note.value.renote as misskey.entities.Note) : note.value,
|
||||||
);
|
);
|
||||||
const isMyRenote = $i && $i.id === note.value.userId;
|
const isMyRenote = $i && $i.id === note.value.userId;
|
||||||
|
@ -385,7 +385,7 @@ function react(viaKeyboard = false): void {
|
||||||
(reaction) => {
|
(reaction) => {
|
||||||
os.api("notes/reactions/create", {
|
os.api("notes/reactions/create", {
|
||||||
noteId: appearNote.value.id,
|
noteId: appearNote.value.id,
|
||||||
reaction: reaction,
|
reaction,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
|
@ -516,7 +516,7 @@ function showRenoteMenu(viaKeyboard = false): void {
|
||||||
],
|
],
|
||||||
renoteTime.value,
|
renoteTime.value,
|
||||||
{
|
{
|
||||||
viaKeyboard: viaKeyboard,
|
viaKeyboard,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -560,7 +560,7 @@ function readPromo() {
|
||||||
isDeleted.value = true;
|
isDeleted.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let postIsExpanded = ref(false);
|
const postIsExpanded = ref(false);
|
||||||
|
|
||||||
function setPostExpanded(val: boolean) {
|
function setPostExpanded(val: boolean) {
|
||||||
postIsExpanded.value = val;
|
postIsExpanded.value = val;
|
||||||
|
|
|
@ -10,27 +10,27 @@
|
||||||
:class="{ renote: isRenote }"
|
:class="{ renote: isRenote }"
|
||||||
>
|
>
|
||||||
<MkNoteSub
|
<MkNoteSub
|
||||||
v-if="conversation"
|
|
||||||
v-for="note in conversation"
|
v-for="note in conversation"
|
||||||
|
v-if="conversation"
|
||||||
:key="note.id"
|
:key="note.id"
|
||||||
class="reply-to"
|
class="reply-to"
|
||||||
:note="note"
|
:note="note"
|
||||||
:detailedView="true"
|
:detailed-view="true"
|
||||||
/>
|
/>
|
||||||
<MkLoading v-else-if="note.reply" mini />
|
<MkLoading v-else-if="note.reply" mini />
|
||||||
<MkNoteSub
|
<MkNoteSub
|
||||||
v-if="note.reply"
|
v-if="note.reply"
|
||||||
:note="note.reply"
|
:note="note.reply"
|
||||||
class="reply-to"
|
class="reply-to"
|
||||||
:detailedView="true"
|
:detailed-view="true"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<MkNote
|
<MkNote
|
||||||
ref="noteEl"
|
ref="noteEl"
|
||||||
@contextmenu.stop="onContextmenu"
|
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
:note="note"
|
:note="note"
|
||||||
detailedView
|
detailed-view
|
||||||
|
@contextmenu.stop="onContextmenu"
|
||||||
></MkNote>
|
></MkNote>
|
||||||
|
|
||||||
<MkTab v-model="tab" :style="'underline'" @update:modelValue="loadTab">
|
<MkTab v-model="tab" :style="'underline'" @update:modelValue="loadTab">
|
||||||
|
@ -41,22 +41,22 @@
|
||||||
}}</span>
|
}}</span>
|
||||||
{{ i18n.ts._notification._types.reply }}
|
{{ i18n.ts._notification._types.reply }}
|
||||||
</option>
|
</option>
|
||||||
<option value="renotes" v-if="note.renoteCount > 0">
|
<option v-if="note.renoteCount > 0" value="renotes">
|
||||||
<!-- <i class="ph-repeat ph-bold ph-lg"></i> -->
|
<!-- <i class="ph-repeat ph-bold ph-lg"></i> -->
|
||||||
<span class="count">{{ note.renoteCount }}</span>
|
<span class="count">{{ note.renoteCount }}</span>
|
||||||
{{ i18n.ts._notification._types.renote }}
|
{{ i18n.ts._notification._types.renote }}
|
||||||
</option>
|
</option>
|
||||||
<option value="reactions" v-if="reactionsCount > 0">
|
<option v-if="reactionsCount > 0" value="reactions">
|
||||||
<!-- <i class="ph-smiley ph-bold ph-lg"></i> -->
|
<!-- <i class="ph-smiley ph-bold ph-lg"></i> -->
|
||||||
<span class="count">{{ reactionsCount }}</span>
|
<span class="count">{{ reactionsCount }}</span>
|
||||||
{{ i18n.ts.reaction }}
|
{{ i18n.ts.reaction }}
|
||||||
</option>
|
</option>
|
||||||
<option value="quotes" v-if="directQuotes?.length > 0">
|
<option v-if="directQuotes?.length > 0" value="quotes">
|
||||||
<!-- <i class="ph-quotes ph-bold ph-lg"></i> -->
|
<!-- <i class="ph-quotes ph-bold ph-lg"></i> -->
|
||||||
<span class="count">{{ directQuotes.length }}</span>
|
<span class="count">{{ directQuotes.length }}</span>
|
||||||
{{ i18n.ts._notification._types.quote }}
|
{{ i18n.ts._notification._types.quote }}
|
||||||
</option>
|
</option>
|
||||||
<option value="clips" v-if="clips?.length > 0">
|
<option v-if="clips?.length > 0" value="clips">
|
||||||
<!-- <i class="ph-paperclip ph-bold ph-lg"></i> -->
|
<!-- <i class="ph-paperclip ph-bold ph-lg"></i> -->
|
||||||
<span class="count">{{ clips.length }}</span>
|
<span class="count">{{ clips.length }}</span>
|
||||||
{{ i18n.ts.clips }}
|
{{ i18n.ts.clips }}
|
||||||
|
@ -64,26 +64,26 @@
|
||||||
</MkTab>
|
</MkTab>
|
||||||
|
|
||||||
<MkNoteSub
|
<MkNoteSub
|
||||||
v-if="directReplies && tab === 'replies'"
|
|
||||||
v-for="note in directReplies"
|
v-for="note in directReplies"
|
||||||
|
v-if="directReplies && tab === 'replies'"
|
||||||
:key="note.id"
|
:key="note.id"
|
||||||
:note="note"
|
:note="note"
|
||||||
class="reply"
|
class="reply"
|
||||||
:conversation="replies"
|
:conversation="replies"
|
||||||
:detailedView="true"
|
:detailed-view="true"
|
||||||
:parentId="note.id"
|
:parent-id="note.id"
|
||||||
/>
|
/>
|
||||||
<MkLoading v-else-if="tab === 'replies' && note.repliesCount > 0" />
|
<MkLoading v-else-if="tab === 'replies' && note.repliesCount > 0" />
|
||||||
|
|
||||||
<MkNoteSub
|
<MkNoteSub
|
||||||
v-if="directQuotes && tab === 'quotes'"
|
|
||||||
v-for="note in directQuotes"
|
v-for="note in directQuotes"
|
||||||
|
v-if="directQuotes && tab === 'quotes'"
|
||||||
:key="note.id"
|
:key="note.id"
|
||||||
:note="note"
|
:note="note"
|
||||||
class="reply"
|
class="reply"
|
||||||
:conversation="replies"
|
:conversation="replies"
|
||||||
:detailedView="true"
|
:detailed-view="true"
|
||||||
:parentId="note.id"
|
:parent-id="note.id"
|
||||||
/>
|
/>
|
||||||
<MkLoading v-else-if="tab === 'quotes' && directQuotes.length > 0" />
|
<MkLoading v-else-if="tab === 'quotes' && directQuotes.length > 0" />
|
||||||
|
|
||||||
|
@ -94,8 +94,8 @@
|
||||||
:pagination="pagination"
|
:pagination="pagination"
|
||||||
> -->
|
> -->
|
||||||
<MkUserCardMini
|
<MkUserCardMini
|
||||||
v-if="tab === 'renotes' && renotes"
|
|
||||||
v-for="item in renotes"
|
v-for="item in renotes"
|
||||||
|
v-if="tab === 'renotes' && renotes"
|
||||||
:key="item.user.id"
|
:key="item.user.id"
|
||||||
:user="item.user"
|
:user="item.user"
|
||||||
:with-chart="false"
|
:with-chart="false"
|
||||||
|
@ -151,11 +151,12 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onUnmounted, onUpdated, ref } from "vue";
|
import { onMounted, onUnmounted, onUpdated, ref } from "vue";
|
||||||
import * as misskey from "firefish-js";
|
import type * as misskey from "firefish-js";
|
||||||
|
import type { NoteUpdatedEvent } from "firefish-js/built/streaming.types";
|
||||||
import MkTab from "@/components/MkTab.vue";
|
import MkTab from "@/components/MkTab.vue";
|
||||||
import MkNote from "@/components/MkNote.vue";
|
import MkNote from "@/components/MkNote.vue";
|
||||||
import MkNoteSub from "@/components/MkNoteSub.vue";
|
import MkNoteSub from "@/components/MkNoteSub.vue";
|
||||||
import XRenoteButton from "@/components/MkRenoteButton.vue";
|
import type XRenoteButton from "@/components/MkRenoteButton.vue";
|
||||||
import MkUserCardMini from "@/components/MkUserCardMini.vue";
|
import MkUserCardMini from "@/components/MkUserCardMini.vue";
|
||||||
import MkReactedUsers from "@/components/MkReactedUsers.vue";
|
import MkReactedUsers from "@/components/MkReactedUsers.vue";
|
||||||
import { pleaseLogin } from "@/scripts/please-login";
|
import { pleaseLogin } from "@/scripts/please-login";
|
||||||
|
@ -170,16 +171,15 @@ import { getNoteMenu } from "@/scripts/get-note-menu";
|
||||||
import { useNoteCapture } from "@/scripts/use-note-capture";
|
import { useNoteCapture } from "@/scripts/use-note-capture";
|
||||||
import { deepClone } from "@/scripts/clone";
|
import { deepClone } from "@/scripts/clone";
|
||||||
import { stream } from "@/stream";
|
import { stream } from "@/stream";
|
||||||
import { NoteUpdatedEvent } from "firefish-js/built/streaming.types";
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
note: misskey.entities.Note;
|
note: misskey.entities.Note;
|
||||||
pinned?: boolean;
|
pinned?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let tab = ref("replies");
|
const tab = ref("replies");
|
||||||
|
|
||||||
let note = ref(deepClone(props.note));
|
const note = ref(deepClone(props.note));
|
||||||
|
|
||||||
const softMuteReasonI18nSrc = (what?: string) => {
|
const softMuteReasonI18nSrc = (what?: string) => {
|
||||||
if (what === "note") return i18n.ts.userSaysSomethingReason;
|
if (what === "note") return i18n.ts.userSaysSomethingReason;
|
||||||
|
@ -214,12 +214,12 @@ const muted = ref(
|
||||||
);
|
);
|
||||||
const translation = ref(null);
|
const translation = ref(null);
|
||||||
const translating = ref(false);
|
const translating = ref(false);
|
||||||
let conversation = ref<null | misskey.entities.Note[]>([]);
|
const conversation = ref<null | misskey.entities.Note[]>([]);
|
||||||
const replies = ref<misskey.entities.Note[]>([]);
|
const replies = ref<misskey.entities.Note[]>([]);
|
||||||
let directReplies = ref<null | misskey.entities.Note[]>([]);
|
const directReplies = ref<null | misskey.entities.Note[]>([]);
|
||||||
let directQuotes = ref<null | misskey.entities.Note[]>([]);
|
const directQuotes = ref<null | misskey.entities.Note[]>([]);
|
||||||
let clips = ref();
|
const clips = ref();
|
||||||
let renotes = ref();
|
const renotes = ref();
|
||||||
let isScrolling;
|
let isScrolling;
|
||||||
|
|
||||||
const reactionsCount = Object.values(props.note.reactions).reduce(
|
const reactionsCount = Object.values(props.note.reactions).reduce(
|
||||||
|
@ -238,7 +238,7 @@ const keymap = {
|
||||||
|
|
||||||
useNoteCapture({
|
useNoteCapture({
|
||||||
rootEl: el,
|
rootEl: el,
|
||||||
note: note,
|
note,
|
||||||
isDeletedRef: isDeleted,
|
isDeletedRef: isDeleted,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -260,7 +260,7 @@ function react(viaKeyboard = false): void {
|
||||||
(reaction) => {
|
(reaction) => {
|
||||||
os.api("notes/reactions/create", {
|
os.api("notes/reactions/create", {
|
||||||
noteId: note.value.id,
|
noteId: note.value.id,
|
||||||
reaction: reaction,
|
reaction,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
|
|
|
@ -49,7 +49,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
|
|
||||||
import {} from "vue";
|
|
||||||
import type * as misskey from "firefish-js";
|
import type * as misskey from "firefish-js";
|
||||||
import { defaultStore } from "@/store";
|
import { defaultStore } from "@/store";
|
||||||
import MkVisibility from "@/components/MkVisibility.vue";
|
import MkVisibility from "@/components/MkVisibility.vue";
|
||||||
|
@ -63,7 +62,7 @@ const props = defineProps<{
|
||||||
pinned?: boolean;
|
pinned?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let note = ref(props.note);
|
const note = ref(props.note);
|
||||||
|
|
||||||
const showTicker =
|
const showTicker =
|
||||||
defaultStore.state.instanceTicker === "always" ||
|
defaultStore.state.instanceTicker === "always" ||
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-size="{ min: [350, 500] }" class="fefdfafb">
|
<div v-size="{ min: [350, 500] }" class="fefdfafb">
|
||||||
<MkAvatar class="avatar" :user="$i" disableLink />
|
<MkAvatar class="avatar" :user="$i" disable-link />
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<MkUserName :user="$i" />
|
<MkUserName :user="$i" />
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
:text="preprocess(text).trim()"
|
:text="preprocess(text).trim()"
|
||||||
:author="$i"
|
:author="$i"
|
||||||
:i="$i"
|
:i="$i"
|
||||||
advancedMfm
|
advanced-mfm
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import * as misskey from "firefish-js";
|
import type * as misskey from "firefish-js";
|
||||||
import XNoteHeader from "@/components/MkNoteHeader.vue";
|
import XNoteHeader from "@/components/MkNoteHeader.vue";
|
||||||
import MkSubNoteContent from "@/components/MkSubNoteContent.vue";
|
import MkSubNoteContent from "@/components/MkSubNoteContent.vue";
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<article
|
<article
|
||||||
v-if="!muted.muted || muted.what === 'reply'"
|
v-if="!muted.muted || muted.what === 'reply'"
|
||||||
|
:id="detailedView ? appearNote.id : null"
|
||||||
ref="el"
|
ref="el"
|
||||||
v-size="{ max: [450, 500] }"
|
v-size="{ max: [450, 500] }"
|
||||||
class="wrpstxzv"
|
class="wrpstxzv"
|
||||||
:id="detailedView ? appearNote.id : null"
|
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
:class="{
|
:class="{
|
||||||
children: depth > 1,
|
children: depth > 1,
|
||||||
|
@ -16,8 +16,8 @@
|
||||||
<div v-if="conversation && depth > 1" class="line"></div>
|
<div v-if="conversation && depth > 1" class="line"></div>
|
||||||
<div
|
<div
|
||||||
class="main"
|
class="main"
|
||||||
@click="noteClick"
|
|
||||||
:style="{ cursor: expandOnNoteClick ? 'pointer' : '' }"
|
:style="{ cursor: expandOnNoteClick ? 'pointer' : '' }"
|
||||||
|
@click="noteClick"
|
||||||
>
|
>
|
||||||
<div class="avatar-container">
|
<div class="avatar-container">
|
||||||
<MkAvatar class="avatar" :user="appearNote.user" />
|
<MkAvatar class="avatar" :user="appearNote.user" />
|
||||||
|
@ -32,9 +32,9 @@
|
||||||
<MkSubNoteContent
|
<MkSubNoteContent
|
||||||
class="text"
|
class="text"
|
||||||
:note="note"
|
:note="note"
|
||||||
:parentId="parentId"
|
:parent-id="parentId"
|
||||||
:conversation="conversation"
|
:conversation="conversation"
|
||||||
:detailedView="detailedView"
|
:detailed-view="detailedView"
|
||||||
@focusfooter="footerEl.focus()"
|
@focusfooter="footerEl.focus()"
|
||||||
/>
|
/>
|
||||||
<div v-if="translating || translation" class="translation">
|
<div v-if="translating || translation" class="translation">
|
||||||
|
@ -117,9 +117,9 @@
|
||||||
appearNote.myReaction != null
|
appearNote.myReaction != null
|
||||||
"
|
"
|
||||||
ref="reactButton"
|
ref="reactButton"
|
||||||
|
v-tooltip.noDelay.bottom="i18n.ts.removeReaction"
|
||||||
class="button _button reacted"
|
class="button _button reacted"
|
||||||
@click.stop="undoReact(appearNote)"
|
@click.stop="undoReact(appearNote)"
|
||||||
v-tooltip.noDelay.bottom="i18n.ts.removeReaction"
|
|
||||||
>
|
>
|
||||||
<i class="ph-minus ph-bold ph-lg"></i>
|
<i class="ph-minus ph-bold ph-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
|
@ -137,17 +137,17 @@
|
||||||
</div>
|
</div>
|
||||||
<template v-if="conversation">
|
<template v-if="conversation">
|
||||||
<MkNoteSub
|
<MkNoteSub
|
||||||
v-if="replyLevel < 11 && depth < 5"
|
|
||||||
v-for="reply in replies"
|
v-for="reply in replies"
|
||||||
|
v-if="replyLevel < 11 && depth < 5"
|
||||||
:key="reply.id"
|
:key="reply.id"
|
||||||
:note="reply"
|
:note="reply"
|
||||||
class="reply"
|
class="reply"
|
||||||
:class="{ single: replies.length == 1 }"
|
:class="{ single: replies.length == 1 }"
|
||||||
:conversation="conversation"
|
:conversation="conversation"
|
||||||
:depth="replies.length == 1 ? depth : depth + 1"
|
:depth="replies.length == 1 ? depth : depth + 1"
|
||||||
:replyLevel="replyLevel + 1"
|
:reply-level="replyLevel + 1"
|
||||||
:parentId="appearNote.id"
|
:parent-id="appearNote.id"
|
||||||
:detailedView="detailedView"
|
:detailed-view="detailedView"
|
||||||
/>
|
/>
|
||||||
<div v-else-if="replies.length > 0" class="more">
|
<div v-else-if="replies.length > 0" class="more">
|
||||||
<div class="line"></div>
|
<div class="line"></div>
|
||||||
|
@ -177,9 +177,9 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { inject, ref, computed } from "vue";
|
import { computed, inject, ref } from "vue";
|
||||||
import type { Ref } from "vue";
|
import type { Ref } from "vue";
|
||||||
import * as misskey from "firefish-js";
|
import type * as misskey from "firefish-js";
|
||||||
import XNoteHeader from "@/components/MkNoteHeader.vue";
|
import XNoteHeader from "@/components/MkNoteHeader.vue";
|
||||||
import MkSubNoteContent from "@/components/MkSubNoteContent.vue";
|
import MkSubNoteContent from "@/components/MkSubNoteContent.vue";
|
||||||
import XReactionsViewer from "@/components/MkReactionsViewer.vue";
|
import XReactionsViewer from "@/components/MkReactionsViewer.vue";
|
||||||
|
@ -223,7 +223,7 @@ const props = withDefaults(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let note = ref(deepClone(props.note));
|
const note = ref(deepClone(props.note));
|
||||||
|
|
||||||
const softMuteReasonI18nSrc = (what?: string) => {
|
const softMuteReasonI18nSrc = (what?: string) => {
|
||||||
if (what === "note") return i18n.ts.userSaysSomethingReason;
|
if (what === "note") return i18n.ts.userSaysSomethingReason;
|
||||||
|
@ -247,7 +247,7 @@ const menuButton = ref<HTMLElement>();
|
||||||
const starButton = ref<InstanceType<typeof XStarButton>>();
|
const starButton = ref<InstanceType<typeof XStarButton>>();
|
||||||
const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
|
const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
|
||||||
const reactButton = ref<HTMLElement>();
|
const reactButton = ref<HTMLElement>();
|
||||||
let appearNote = computed(() =>
|
const appearNote = computed(() =>
|
||||||
isRenote ? (note.value.renote as misskey.entities.Note) : note.value,
|
isRenote ? (note.value.renote as misskey.entities.Note) : note.value,
|
||||||
);
|
);
|
||||||
const isDeleted = ref(false);
|
const isDeleted = ref(false);
|
||||||
|
@ -291,7 +291,7 @@ function react(viaKeyboard = false): void {
|
||||||
(reaction) => {
|
(reaction) => {
|
||||||
os.api("notes/reactions/create", {
|
os.api("notes/reactions/create", {
|
||||||
noteId: appearNote.value.id,
|
noteId: appearNote.value.id,
|
||||||
reaction: reaction,
|
reaction,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #default="{ items: notes }">
|
<template #default="{ items: notes }">
|
||||||
<div class="giivymft" :class="{ noGap }" ref="tlEl">
|
<div ref="tlEl" class="giivymft" :class="{ noGap }">
|
||||||
<XList
|
<XList
|
||||||
ref="notes"
|
ref="notes"
|
||||||
v-slot="{ item: note }"
|
v-slot="{ item: note }"
|
||||||
|
|
|
@ -219,7 +219,7 @@
|
||||||
<MkFollowButton
|
<MkFollowButton
|
||||||
:user="notification.user"
|
:user="notification.user"
|
||||||
:full="true"
|
:full="true"
|
||||||
:hideMenu="true"
|
:hide-menu="true"
|
||||||
/></div
|
/></div
|
||||||
></span>
|
></span>
|
||||||
<span
|
<span
|
||||||
|
@ -273,8 +273,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, onMounted, onUnmounted, watch } from "vue";
|
import { onMounted, onUnmounted, ref, watch } from "vue";
|
||||||
import * as misskey from "firefish-js";
|
import type * as misskey from "firefish-js";
|
||||||
import XReactionIcon from "@/components/MkReactionIcon.vue";
|
import XReactionIcon from "@/components/MkReactionIcon.vue";
|
||||||
import MkFollowButton from "@/components/MkFollowButton.vue";
|
import MkFollowButton from "@/components/MkFollowButton.vue";
|
||||||
import XReactionTooltip from "@/components/MkReactionTooltip.vue";
|
import XReactionTooltip from "@/components/MkReactionTooltip.vue";
|
||||||
|
@ -310,8 +310,7 @@ const defaultReaction = ["⭐", "👍", "❤️"].includes(instance.defaultReact
|
||||||
? instance.defaultReaction
|
? instance.defaultReaction
|
||||||
: "⭐";
|
: "⭐";
|
||||||
|
|
||||||
let readObserver: IntersectionObserver | undefined;
|
let readObserver: IntersectionObserver | undefined, connection;
|
||||||
let connection;
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (!props.notification.isRead) {
|
if (!props.notification.isRead) {
|
||||||
|
|
|
@ -41,7 +41,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref } from "vue";
|
import { computed, ref } from "vue";
|
||||||
|
|
||||||
import {} from "vue";
|
|
||||||
import { notificationTypes } from "firefish-js";
|
import { notificationTypes } from "firefish-js";
|
||||||
import MkSwitch from "./form/switch.vue";
|
import MkSwitch from "./form/switch.vue";
|
||||||
import MkInfo from "./MkInfo.vue";
|
import MkInfo from "./MkInfo.vue";
|
||||||
|
@ -65,12 +64,12 @@ const props = withDefaults(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let includingTypes = computed(() => props.includingTypes || []);
|
const includingTypes = computed(() => props.includingTypes || []);
|
||||||
|
|
||||||
const dialog = ref<InstanceType<typeof XModalWindow>>();
|
const dialog = ref<InstanceType<typeof XModalWindow>>();
|
||||||
|
|
||||||
let typesMap = ref<Record<(typeof notificationTypes)[number], boolean>>({});
|
const typesMap = ref<Record<(typeof notificationTypes)[number], boolean>>({});
|
||||||
let useGlobalSetting = ref(
|
const useGlobalSetting = ref(
|
||||||
(includingTypes.value === null || includingTypes.value.length === 0) &&
|
(includingTypes.value === null || includingTypes.value.length === 0) &&
|
||||||
props.showGlobalToggle,
|
props.showGlobalToggle,
|
||||||
);
|
);
|
||||||
|
|
|
@ -28,7 +28,7 @@ const emit = defineEmits<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const zIndex = os.claimZIndex("high");
|
const zIndex = os.claimZIndex("high");
|
||||||
let showing = ref(true);
|
const showing = ref(true);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
"
|
"
|
||||||
:key="notification.id"
|
:key="notification.id"
|
||||||
:note="notification.note"
|
:note="notification.note"
|
||||||
:collapsedReply="
|
:collapsed-reply="
|
||||||
notification.type === 'reply' ||
|
notification.type === 'reply' ||
|
||||||
(notification.type === 'mention' &&
|
(notification.type === 'mention' &&
|
||||||
notification.note.replyId != null)
|
notification.note.replyId != null)
|
||||||
|
@ -46,9 +46,10 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onUnmounted, onMounted, computed, ref } from "vue";
|
import { computed, onMounted, onUnmounted, ref } from "vue";
|
||||||
import { notificationTypes } from "firefish-js";
|
import type { notificationTypes } from "firefish-js";
|
||||||
import MkPagination, { Paging } from "@/components/MkPagination.vue";
|
import type { Paging } from "@/components/MkPagination.vue";
|
||||||
|
import MkPagination from "@/components/MkPagination.vue";
|
||||||
import XNotification from "@/components/MkNotification.vue";
|
import XNotification from "@/components/MkNotification.vue";
|
||||||
import XList from "@/components/MkDateSeparatedList.vue";
|
import XList from "@/components/MkDateSeparatedList.vue";
|
||||||
import XNote from "@/components/MkNote.vue";
|
import XNote from "@/components/MkNote.vue";
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
:buttons-left="buttonsLeft"
|
:buttons-left="buttonsLeft"
|
||||||
:buttons-right="buttonsRight"
|
:buttons-right="buttonsRight"
|
||||||
:contextmenu="contextmenu"
|
:contextmenu="contextmenu"
|
||||||
@closed="$emit('closed')"
|
|
||||||
class="page-window"
|
class="page-window"
|
||||||
|
@closed="$emit('closed')"
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<template v-if="pageMetadata?.value">
|
<template v-if="pageMetadata?.value">
|
||||||
|
@ -30,7 +30,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ComputedRef, provide, ref, computed } from "vue";
|
import type { ComputedRef } from "vue";
|
||||||
|
import { computed, provide, ref } from "vue";
|
||||||
import RouterView from "@/components/global/RouterView.vue";
|
import RouterView from "@/components/global/RouterView.vue";
|
||||||
import XWindow from "@/components/MkWindow.vue";
|
import XWindow from "@/components/MkWindow.vue";
|
||||||
import { popout as _popout } from "@/scripts/popout";
|
import { popout as _popout } from "@/scripts/popout";
|
||||||
|
@ -39,7 +40,8 @@ import { url } from "@/config";
|
||||||
import { mainRouter, routes } from "@/router";
|
import { mainRouter, routes } from "@/router";
|
||||||
import { Router } from "@/nirax";
|
import { Router } from "@/nirax";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
import { PageMetadata, provideMetadataReceiver } from "@/scripts/page-metadata";
|
import type { PageMetadata } from "@/scripts/page-metadata";
|
||||||
|
import { provideMetadataReceiver } from "@/scripts/page-metadata";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
initialPath: string;
|
initialPath: string;
|
||||||
|
@ -51,8 +53,8 @@ defineEmits<{
|
||||||
|
|
||||||
const router = new Router(routes, props.initialPath);
|
const router = new Router(routes, props.initialPath);
|
||||||
|
|
||||||
let pageMetadata = ref<null | ComputedRef<PageMetadata>>();
|
const pageMetadata = ref<null | ComputedRef<PageMetadata>>();
|
||||||
let windowEl = ref<InstanceType<typeof XWindow>>();
|
const windowEl = ref<InstanceType<typeof XWindow>>();
|
||||||
const history = ref<{ path: string; key: any }[]>([
|
const history = ref<{ path: string; key: any }[]>([
|
||||||
{
|
{
|
||||||
path: router.getCurrentPath(),
|
path: router.getCurrentPath(),
|
||||||
|
|
|
@ -63,29 +63,22 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {
|
import type { ComputedRef } from "vue";
|
||||||
computed,
|
import { computed, isRef, onActivated, onDeactivated, ref, watch } from "vue";
|
||||||
ComputedRef,
|
import type * as misskey from "firefish-js";
|
||||||
isRef,
|
|
||||||
onActivated,
|
|
||||||
onDeactivated,
|
|
||||||
ref,
|
|
||||||
watch,
|
|
||||||
} from "vue";
|
|
||||||
import * as misskey from "firefish-js";
|
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
import {
|
import {
|
||||||
onScrollTop,
|
|
||||||
isTopVisible,
|
|
||||||
getScrollPosition,
|
|
||||||
getScrollContainer,
|
getScrollContainer,
|
||||||
|
getScrollPosition,
|
||||||
|
isTopVisible,
|
||||||
|
onScrollTop,
|
||||||
} from "@/scripts/scroll";
|
} from "@/scripts/scroll";
|
||||||
import MkButton from "@/components/MkButton.vue";
|
import MkButton from "@/components/MkButton.vue";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
|
|
||||||
export type Paging<
|
export interface Paging<
|
||||||
E extends keyof misskey.Endpoints = keyof misskey.Endpoints,
|
E extends keyof misskey.Endpoints = keyof misskey.Endpoints,
|
||||||
> = {
|
> {
|
||||||
endpoint: E;
|
endpoint: E;
|
||||||
limit: number;
|
limit: number;
|
||||||
params?:
|
params?:
|
||||||
|
@ -104,7 +97,7 @@ export type Paging<
|
||||||
reversed?: boolean;
|
reversed?: boolean;
|
||||||
|
|
||||||
offsetMode?: boolean;
|
offsetMode?: boolean;
|
||||||
};
|
}
|
||||||
|
|
||||||
const SECOND_FETCH_LIMIT = 30;
|
const SECOND_FETCH_LIMIT = 30;
|
||||||
|
|
||||||
|
@ -123,7 +116,10 @@ const emit = defineEmits<{
|
||||||
(ev: "queue", count: number): void;
|
(ev: "queue", count: number): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
type Item = { id: string; [another: string]: unknown };
|
interface Item {
|
||||||
|
id: string;
|
||||||
|
[another: string]: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
const rootEl = ref<HTMLElement>();
|
const rootEl = ref<HTMLElement>();
|
||||||
const items = ref<Item[]>([]);
|
const items = ref<Item[]>([]);
|
||||||
|
@ -207,12 +203,12 @@ const refresh = async (): void => {
|
||||||
})
|
})
|
||||||
.then(
|
.then(
|
||||||
(res) => {
|
(res) => {
|
||||||
let ids = items.value.reduce(
|
const ids = items.value.reduce(
|
||||||
(a, b) => {
|
(a, b) => {
|
||||||
a[b.id] = true;
|
a[b.id] = true;
|
||||||
return a;
|
return a;
|
||||||
},
|
},
|
||||||
{} as { [id: string]: boolean },
|
{} as Record<string, boolean>,
|
||||||
);
|
);
|
||||||
|
|
||||||
for (let i = 0; i < res.length; i++) {
|
for (let i = 0; i < res.length; i++) {
|
||||||
|
@ -364,7 +360,7 @@ const prepend = (item: Item): void => {
|
||||||
// オーバーフローしたら古いアイテムは捨てる
|
// オーバーフローしたら古いアイテムは捨てる
|
||||||
if (items.value.length >= props.displayLimit) {
|
if (items.value.length >= props.displayLimit) {
|
||||||
// このやり方だとVue 3.2以降アニメーションが動かなくなる
|
// このやり方だとVue 3.2以降アニメーションが動かなくなる
|
||||||
//items.value = items.value.slice(-props.displayLimit);
|
// items.value = items.value.slice(-props.displayLimit);
|
||||||
while (items.value.length >= props.displayLimit) {
|
while (items.value.length >= props.displayLimit) {
|
||||||
items.value.shift();
|
items.value.shift();
|
||||||
}
|
}
|
||||||
|
@ -394,7 +390,7 @@ const prepend = (item: Item): void => {
|
||||||
// オーバーフローしたら古いアイテムは捨てる
|
// オーバーフローしたら古いアイテムは捨てる
|
||||||
if (items.value.length >= props.displayLimit) {
|
if (items.value.length >= props.displayLimit) {
|
||||||
// このやり方だとVue 3.2以降アニメーションが動かなくなる
|
// このやり方だとVue 3.2以降アニメーションが動かなくなる
|
||||||
//this.items = items.value.slice(0, props.displayLimit);
|
// this.items = items.value.slice(0, props.displayLimit);
|
||||||
while (items.value.length >= props.displayLimit) {
|
while (items.value.length >= props.displayLimit) {
|
||||||
items.value.pop();
|
items.value.pop();
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref } from "vue";
|
import { computed, ref } from "vue";
|
||||||
import * as misskey from "firefish-js";
|
import type * as misskey from "firefish-js";
|
||||||
import { sum } from "@/scripts/array";
|
import { sum } from "@/scripts/array";
|
||||||
import { pleaseLogin } from "@/scripts/please-login";
|
import { pleaseLogin } from "@/scripts/please-login";
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
</MkInput>
|
</MkInput>
|
||||||
<button
|
<button
|
||||||
class="_button"
|
class="_button"
|
||||||
@click="remove(i)"
|
|
||||||
:aria-label="i18n.t('remove')"
|
:aria-label="i18n.t('remove')"
|
||||||
|
@click="remove(i)"
|
||||||
>
|
>
|
||||||
<i class="ph-x ph-bold ph-lg"></i>
|
<i class="ph-x ph-bold ph-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
:z-priority="'high'"
|
:z-priority="'high'"
|
||||||
:src="src"
|
:src="src"
|
||||||
:transparent-bg="true"
|
:transparent-bg="true"
|
||||||
|
tabindex="-1"
|
||||||
@click="modal?.close()"
|
@click="modal?.close()"
|
||||||
@closed="emit('closed')"
|
@closed="emit('closed')"
|
||||||
tabindex="-1"
|
|
||||||
>
|
>
|
||||||
<MkMenu
|
<MkMenu
|
||||||
:items="items"
|
:items="items"
|
||||||
|
@ -28,7 +28,7 @@ import { ref } from "vue";
|
||||||
|
|
||||||
import MkModal from "./MkModal.vue";
|
import MkModal from "./MkModal.vue";
|
||||||
import MkMenu from "./MkMenu.vue";
|
import MkMenu from "./MkMenu.vue";
|
||||||
import { MenuItem } from "@/types/menu";
|
import type { MenuItem } from "@/types/menu";
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
items: MenuItem[];
|
items: MenuItem[];
|
||||||
|
@ -43,7 +43,7 @@ const emit = defineEmits<{
|
||||||
(ev: "closed"): void;
|
(ev: "closed"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let modal = ref<InstanceType<typeof MkModal>>();
|
const modal = ref<InstanceType<typeof MkModal>>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -86,8 +86,8 @@
|
||||||
{{ i18n.ts.quoteAttached
|
{{ i18n.ts.quoteAttached
|
||||||
}}<button
|
}}<button
|
||||||
class="_button"
|
class="_button"
|
||||||
@click="quoteId = null"
|
|
||||||
:aria-label="i18n.t('removeQuote')"
|
:aria-label="i18n.t('removeQuote')"
|
||||||
|
@click="quoteId = null"
|
||||||
>
|
>
|
||||||
<i class="ph-x ph-bold ph-lg"></i>
|
<i class="ph-x ph-bold ph-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
|
@ -99,8 +99,8 @@
|
||||||
<MkAcct :user="u" />
|
<MkAcct :user="u" />
|
||||||
<button
|
<button
|
||||||
class="_button"
|
class="_button"
|
||||||
@click="removeVisibleUser(u)"
|
|
||||||
:aria-label="i18n.t('removeRecipient')"
|
:aria-label="i18n.t('removeRecipient')"
|
||||||
|
@click="removeVisibleUser(u)"
|
||||||
>
|
>
|
||||||
<i class="ph-x ph-bold ph-lg"></i>
|
<i class="ph-x ph-bold ph-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
|
@ -234,16 +234,16 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {
|
import {
|
||||||
|
computed,
|
||||||
|
defineAsyncComponent,
|
||||||
inject,
|
inject,
|
||||||
watch,
|
|
||||||
nextTick,
|
nextTick,
|
||||||
onMounted,
|
onMounted,
|
||||||
defineAsyncComponent,
|
|
||||||
ref,
|
ref,
|
||||||
computed,
|
watch,
|
||||||
} from "vue";
|
} from "vue";
|
||||||
import * as mfm from "mfm-js";
|
import * as mfm from "mfm-js";
|
||||||
import * as misskey from "firefish-js";
|
import type * as misskey from "firefish-js";
|
||||||
import autosize from "autosize";
|
import autosize from "autosize";
|
||||||
import insertTextAtCursor from "insert-text-at-cursor";
|
import insertTextAtCursor from "insert-text-at-cursor";
|
||||||
import { length } from "stringz";
|
import { length } from "stringz";
|
||||||
|
@ -315,40 +315,42 @@ const cwInputEl = ref<HTMLInputElement | null>(null);
|
||||||
const hashtagsInputEl = ref<HTMLInputElement | null>(null);
|
const hashtagsInputEl = ref<HTMLInputElement | null>(null);
|
||||||
const visibilityButton = ref<HTMLElement | null>(null);
|
const visibilityButton = ref<HTMLElement | null>(null);
|
||||||
|
|
||||||
let posting = ref(false);
|
const posting = ref(false);
|
||||||
let text = ref(props.initialText ?? "");
|
const text = ref(props.initialText ?? "");
|
||||||
let files = ref(props.initialFiles ?? []);
|
const files = ref(props.initialFiles ?? []);
|
||||||
let poll = ref<{
|
const poll = ref<{
|
||||||
choices: string[];
|
choices: string[];
|
||||||
multiple: boolean;
|
multiple: boolean;
|
||||||
expiresAt: string | null;
|
expiresAt: string | null;
|
||||||
expiredAfter: string | null;
|
expiredAfter: string | null;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
let useCw = ref(false);
|
const useCw = ref(false);
|
||||||
let showPreview = ref(false);
|
const showPreview = ref(false);
|
||||||
let cw = ref<string | null>(null);
|
const cw = ref<string | null>(null);
|
||||||
let localOnly = ref<boolean>(
|
const localOnly = ref<boolean>(
|
||||||
props.initialLocalOnly ?? defaultStore.state.rememberNoteVisibility
|
props.initialLocalOnly ?? defaultStore.state.rememberNoteVisibility
|
||||||
? defaultStore.state.localOnly
|
? defaultStore.state.localOnly
|
||||||
: defaultStore.state.defaultNoteLocalOnly,
|
: defaultStore.state.defaultNoteLocalOnly,
|
||||||
);
|
);
|
||||||
let visibility = ref(
|
const visibility = ref(
|
||||||
props.initialVisibility ??
|
props.initialVisibility ??
|
||||||
((defaultStore.state.rememberNoteVisibility
|
((defaultStore.state.rememberNoteVisibility
|
||||||
? defaultStore.state.visibility
|
? defaultStore.state.visibility
|
||||||
: defaultStore.state
|
: defaultStore.state
|
||||||
.defaultNoteVisibility) as (typeof misskey.noteVisibilities)[number]),
|
.defaultNoteVisibility) as (typeof misskey.noteVisibilities)[number]),
|
||||||
);
|
);
|
||||||
let visibleUsers = ref([]);
|
const visibleUsers = ref([]);
|
||||||
if (props.initialVisibleUsers) {
|
if (props.initialVisibleUsers) {
|
||||||
props.initialVisibleUsers.forEach(pushVisibleUser);
|
props.initialVisibleUsers.forEach(pushVisibleUser);
|
||||||
}
|
}
|
||||||
let autocomplete = ref(null);
|
const autocomplete = ref(null);
|
||||||
let draghover = ref(false);
|
const draghover = ref(false);
|
||||||
let quoteId = ref(null);
|
const quoteId = ref(null);
|
||||||
let hasNotSpecifiedMentions = ref(false);
|
const hasNotSpecifiedMentions = ref(false);
|
||||||
let recentHashtags = ref(JSON.parse(localStorage.getItem("hashtags") || "[]"));
|
const recentHashtags = ref(
|
||||||
let imeText = ref("");
|
JSON.parse(localStorage.getItem("hashtags") || "[]"),
|
||||||
|
);
|
||||||
|
const imeText = ref("");
|
||||||
|
|
||||||
const typing = throttle(3000, () => {
|
const typing = throttle(3000, () => {
|
||||||
if (props.channel) {
|
if (props.channel) {
|
||||||
|
@ -415,8 +417,8 @@ const maxTextLength = computed((): number => {
|
||||||
const canPost = computed((): boolean => {
|
const canPost = computed((): boolean => {
|
||||||
return (
|
return (
|
||||||
!posting.value &&
|
!posting.value &&
|
||||||
(1 <= textLength.value ||
|
(textLength.value >= 1 ||
|
||||||
1 <= files.value.length ||
|
files.value.length >= 1 ||
|
||||||
!!poll.value ||
|
!!poll.value ||
|
||||||
!!props.renote) &&
|
!!props.renote) &&
|
||||||
textLength.value <= maxTextLength.value &&
|
textLength.value <= maxTextLength.value &&
|
||||||
|
@ -816,14 +818,14 @@ function onDrop(ev): void {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region ドライブのファイル
|
// #region ドライブのファイル
|
||||||
const driveFile = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_);
|
const driveFile = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_);
|
||||||
if (driveFile != null && driveFile !== "") {
|
if (driveFile != null && driveFile !== "") {
|
||||||
const file = JSON.parse(driveFile);
|
const file = JSON.parse(driveFile);
|
||||||
files.value.push(file);
|
files.value.push(file);
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
}
|
}
|
||||||
//#endregion
|
// #endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveDraft() {
|
function saveDraft() {
|
||||||
|
@ -896,7 +898,7 @@ async function post() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let token = undefined;
|
let token;
|
||||||
|
|
||||||
if (postAccount.value) {
|
if (postAccount.value) {
|
||||||
const storedAccounts = await getAccounts();
|
const storedAccounts = await getAccounts();
|
||||||
|
@ -976,7 +978,7 @@ function showActions(ev) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let postAccount = ref<misskey.entities.UserDetailed | null>(null);
|
const postAccount = ref<misskey.entities.UserDetailed | null>(null);
|
||||||
|
|
||||||
function openAccountMenu(ev: MouseEvent) {
|
function openAccountMenu(ev: MouseEvent) {
|
||||||
openAccountMenu_(
|
openAccountMenu_(
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
delay-on-touch-only="true"
|
delay-on-touch-only="true"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="file"
|
|
||||||
v-for="element in _files"
|
v-for="element in _files"
|
||||||
:key="element.id"
|
:key="element.id"
|
||||||
|
class="file"
|
||||||
@click="showFileMenu(element, $event)"
|
@click="showFileMenu(element, $event)"
|
||||||
@contextmenu.prevent="showFileMenu(element, $event)"
|
@contextmenu.prevent="showFileMenu(element, $event)"
|
||||||
>
|
>
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineAsyncComponent, ref, computed } from "vue";
|
import { computed, defineAsyncComponent, ref } from "vue";
|
||||||
import { VueDraggable } from "vue-draggable-plus";
|
import { VueDraggable } from "vue-draggable-plus";
|
||||||
import MkDriveFileThumbnail from "@/components/MkDriveFileThumbnail.vue";
|
import MkDriveFileThumbnail from "@/components/MkDriveFileThumbnail.vue";
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
|
@ -105,10 +105,11 @@ async function describe(file) {
|
||||||
{
|
{
|
||||||
done: (result) => {
|
done: (result) => {
|
||||||
if (!result || result.canceled) return;
|
if (!result || result.canceled) return;
|
||||||
let comment = result.result.length === 0 ? null : result.result;
|
const comment =
|
||||||
|
result.result.length === 0 ? null : result.result;
|
||||||
os.api("drive/files/update", {
|
os.api("drive/files/update", {
|
||||||
fileId: file.id,
|
fileId: file.id,
|
||||||
comment: comment,
|
comment,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
file.comment = comment;
|
file.comment = comment;
|
||||||
});
|
});
|
||||||
|
|
|
@ -21,8 +21,7 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { shallowRef } from "vue";
|
import { shallowRef } from "vue";
|
||||||
|
|
||||||
import {} from "vue";
|
import type * as misskey from "firefish-js";
|
||||||
import * as misskey from "firefish-js";
|
|
||||||
import MkModal from "@/components/MkModal.vue";
|
import MkModal from "@/components/MkModal.vue";
|
||||||
import MkPostForm from "@/components/MkPostForm.vue";
|
import MkPostForm from "@/components/MkPostForm.vue";
|
||||||
|
|
||||||
|
@ -48,8 +47,8 @@ const emit = defineEmits<{
|
||||||
(ev: "closed"): void;
|
(ev: "closed"): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let modal = shallowRef<InstanceType<typeof MkModal>>();
|
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
||||||
let form = shallowRef<InstanceType<typeof MkPostForm>>();
|
const form = shallowRef<InstanceType<typeof MkPostForm>>();
|
||||||
|
|
||||||
function onPosted() {
|
function onPosted() {
|
||||||
modal.value.close({
|
modal.value.close({
|
||||||
|
|
|
@ -76,12 +76,12 @@ defineProps<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
// ServiceWorker registration
|
// ServiceWorker registration
|
||||||
let registration = ref<ServiceWorkerRegistration | undefined>();
|
const registration = ref<ServiceWorkerRegistration | undefined>();
|
||||||
// If this browser supports push notification
|
// If this browser supports push notification
|
||||||
let supported = ref(false);
|
const supported = ref(false);
|
||||||
// If this browser has already subscribed to push notification
|
// If this browser has already subscribed to push notification
|
||||||
let pushSubscription = ref<PushSubscription | null>(null);
|
const pushSubscription = ref<PushSubscription | null>(null);
|
||||||
let pushRegistrationInServer = ref<
|
const pushRegistrationInServer = ref<
|
||||||
| {
|
| {
|
||||||
state?: string;
|
state?: string;
|
||||||
key?: string;
|
key?: string;
|
||||||
|
@ -209,6 +209,6 @@ if (navigator.serviceWorker == null) {
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
pushRegistrationInServer: pushRegistrationInServer,
|
pushRegistrationInServer,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -36,8 +36,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, watch, ref } from "vue";
|
import { onMounted, ref, watch } from "vue";
|
||||||
import * as misskey from "firefish-js";
|
import type * as misskey from "firefish-js";
|
||||||
import MkReactionIcon from "@/components/MkReactionIcon.vue";
|
import MkReactionIcon from "@/components/MkReactionIcon.vue";
|
||||||
import MkUserCardMini from "@/components/MkUserCardMini.vue";
|
import MkUserCardMini from "@/components/MkUserCardMini.vue";
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
|
@ -46,10 +46,10 @@ const props = defineProps<{
|
||||||
noteId: misskey.entities.Note["id"];
|
noteId: misskey.entities.Note["id"];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let note = ref<misskey.entities.Note>();
|
const note = ref<misskey.entities.Note>();
|
||||||
let tab = ref<string>();
|
const tab = ref<string>();
|
||||||
let reactions = ref<string[]>();
|
const reactions = ref<string[]>();
|
||||||
let users = ref();
|
const users = ref();
|
||||||
|
|
||||||
watch(tab, async () => {
|
watch(tab, async () => {
|
||||||
const res = await os.api("notes/reactions", {
|
const res = await os.api("notes/reactions", {
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref } from "vue";
|
import { computed, ref } from "vue";
|
||||||
import * as misskey from "firefish-js";
|
import type * as misskey from "firefish-js";
|
||||||
import XDetails from "@/components/MkReactionsViewer.details.vue";
|
import XDetails from "@/components/MkReactionsViewer.details.vue";
|
||||||
import XReactionIcon from "@/components/MkReactionIcon.vue";
|
import XReactionIcon from "@/components/MkReactionIcon.vue";
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref } from "vue";
|
import { computed, ref } from "vue";
|
||||||
import * as misskey from "firefish-js";
|
import type * as misskey from "firefish-js";
|
||||||
import { $i } from "@/account";
|
import { $i } from "@/account";
|
||||||
import XReaction from "@/components/MkReactionsViewer.reaction.vue";
|
import XReaction from "@/components/MkReactionsViewer.reaction.vue";
|
||||||
|
|
||||||
|
|