Compare commits
30 Commits
l10n_devel
...
develop
Author | SHA1 | Date | |
---|---|---|---|
923cacb98a | |||
b1e564b562 | |||
![]() |
0471e457fe | ||
![]() |
260d35e2f0 | ||
![]() |
3ff9d9f4fd | ||
![]() |
27991a3bc8 | ||
![]() |
b5f86e5210 | ||
![]() |
16cde5568d | ||
![]() |
bf07796b6b | ||
![]() |
08b131ec33 | ||
![]() |
1312fe34c1 | ||
![]() |
97563910fa | ||
![]() |
96a7c4a568 | ||
![]() |
fee6f9fcc2 | ||
![]() |
50724b6ab8 | ||
![]() |
e61263cff0 | ||
![]() |
d073fe6b02 | ||
![]() |
ce858a676b | ||
![]() |
733a391d86 | ||
![]() |
0e25a0fb81 | ||
![]() |
1fd87bd2e4 | ||
![]() |
ebc54b1f82 | ||
![]() |
6015254e59 | ||
![]() |
c02f0b3b33 | ||
![]() |
abddd40c09 | ||
![]() |
a865a949b5 | ||
![]() |
0007723405 | ||
![]() |
71188b3463 | ||
![]() |
7f534a41a6 | ||
![]() |
f25963e2c2 |
51
.gitea/workflows/registry.yml
Normal file
51
.gitea/workflows/registry.yml
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
name: release-tag
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'main'
|
||||||
|
jobs:
|
||||||
|
release-image:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
DOCKER_ORG: sendnrw
|
||||||
|
DOCKER_LATEST: latest
|
||||||
|
RUNNER_TOOL_CACHE: /toolcache
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|
||||||
|
- name: Set up Docker BuildX
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
with: # replace it with your local IP
|
||||||
|
config-inline: |
|
||||||
|
[registry."git.send.nrw"]
|
||||||
|
http = true
|
||||||
|
insecure = true
|
||||||
|
|
||||||
|
- name: Login to DockerHub
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: git.send.nrw # replace it with your local IP
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Get Meta
|
||||||
|
id: meta
|
||||||
|
run: |
|
||||||
|
echo REPO_NAME=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $2}') >> $GITHUB_OUTPUT
|
||||||
|
echo REPO_VERSION=$(git describe --tags --always | sed 's/^v//') >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v4
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./Dockerfile
|
||||||
|
platforms: |
|
||||||
|
linux/amd64
|
||||||
|
push: true
|
||||||
|
tags: | # replace it with your local IP and tags
|
||||||
|
git.send.nrw/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.REPO_VERSION }}
|
||||||
|
git.send.nrw/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ env.DOCKER_LATEST }}
|
17
CHANGELOG.md
17
CHANGELOG.md
@@ -6,9 +6,24 @@
|
|||||||
|
|
||||||
### Client
|
### Client
|
||||||
- Feat: 設定の管理が強化されました
|
- Feat: 設定の管理が強化されました
|
||||||
- 自動でバックアップされるように
|
- 内部処理が一新され、安定性とパフォーマンスが向上しました
|
||||||
|
- 全てのクライアント設定がエクスポート(バックアップ)/インポート対象に含まれるようになりました
|
||||||
|
- プラグイン、テーマ、クライアントに追加されたすべてのアカウント情報も含まれるようになりました
|
||||||
|
- 自動で設定データをサーバーにバックアップできるように
|
||||||
|
- 設定→設定のプロファイル→自動バックアップ で有効にできます
|
||||||
|
- 新しいデバイスからログインしたり、ブラウザから設定データが消えてしまったときに自動で復元されます(復元をスキップすることも可能)
|
||||||
- 任意の設定項目をデバイス間で同期できるように
|
- 任意の設定項目をデバイス間で同期できるように
|
||||||
|
- 設定項目の「...」メニュー→「デバイス間で同期」
|
||||||
|
- 同期をオンにした際にサーバーに保存された値とローカルの値が競合する場合はどちらを優先するか選択できます
|
||||||
|
- 任意の設定項目を初期値にリセットできるように
|
||||||
|
- 設定項目の「...」メニュー→「初期値にリセット」
|
||||||
|
- アカウントごとに設定値が分離される設定とそうでないクライアント設定が混在していた(かつ分離するかどうかを設定不可だった)のを、基本的に一律でクライアント全体に適用されるようにし、個別でアカウントごとに異なる設定を行えるように
|
||||||
|
- 設定項目の「...」メニュー→「アカウントで上書き」をオンにすることで、設定値をそのアカウントでだけ適用するようにできます
|
||||||
|
- ログアウトすると設定データもブラウザから消去されるようになりプライバシーが向上しました
|
||||||
|
- 再度ログインすればサーバーのバックアップから設定データを復元可能です
|
||||||
|
- エクスポートした設定データを他のサーバーでインポートして適用すること(設定の持ち運び)が可能になりました
|
||||||
- Feat: 画面を重ねて表示するオプションを実装(実験的)
|
- Feat: 画面を重ねて表示するオプションを実装(実験的)
|
||||||
|
- 設定 → その他 → 実験的機能 → Enable stacking router view
|
||||||
- Enhance: プラグインの管理が強化されました
|
- Enhance: プラグインの管理が強化されました
|
||||||
- インストール/アンインストール/設定の変更時にリロード不要になりました
|
- インストール/アンインストール/設定の変更時にリロード不要になりました
|
||||||
- Enhance: ログアウト時、ブラウザに保存されたWebクライアントのデータを全て消去するように
|
- Enhance: ログアウト時、ブラウザに保存されたWebクライアントのデータを全て消去するように
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
**🌎 **Misskey** is an open source, federated social media platform that's free forever! 🚀**
|
**🌎 **Misskey** is an open source, federated social media platform that's free forever! 🚀**
|
||||||
|
|
||||||
[Learn more](https://misskey-hub.net/)
|
[Learn more](https://misskey-hub.net/)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<a href="https://misskey-hub.net/servers/">
|
<a href="https://misskey-hub.net/servers/">
|
||||||
|
@@ -9,8 +9,6 @@ reset: "Obnovit"
|
|||||||
notifications: "Oznámení"
|
notifications: "Oznámení"
|
||||||
username: "Uživatelské jméno"
|
username: "Uživatelské jméno"
|
||||||
password: "Heslo"
|
password: "Heslo"
|
||||||
initialPasswordForSetup: "Počáteční heslo pro nastavení"
|
|
||||||
initialPasswordIsIncorrect: "Počáteční heslo pro nastavení je nesprávné"
|
|
||||||
forgotPassword: "Zapomenuté heslo"
|
forgotPassword: "Zapomenuté heslo"
|
||||||
fetchingAsApObject: "Načítám data z Fediversu..."
|
fetchingAsApObject: "Načítám data z Fediversu..."
|
||||||
ok: "Potvrdit"
|
ok: "Potvrdit"
|
||||||
@@ -480,8 +478,6 @@ uiLanguage: "Jazyk uživatelského rozhraní"
|
|||||||
aboutX: "O {x}"
|
aboutX: "O {x}"
|
||||||
emojiStyle: "Styl emoji"
|
emojiStyle: "Styl emoji"
|
||||||
native: "Výchozí"
|
native: "Výchozí"
|
||||||
style: "Vzhled"
|
|
||||||
popup: "Vyskakovací okno"
|
|
||||||
showNoteActionsOnlyHover: "Zobrazit akce poznámky jenom při naběhnutí myši"
|
showNoteActionsOnlyHover: "Zobrazit akce poznámky jenom při naběhnutí myši"
|
||||||
noHistory: "Žádná historie"
|
noHistory: "Žádná historie"
|
||||||
signinHistory: "Historie přihlášení"
|
signinHistory: "Historie přihlášení"
|
||||||
|
@@ -1144,7 +1144,7 @@ preventAiLearning: "Verwendung in machinellem Lernen (Generative bzw. Prediktive
|
|||||||
preventAiLearningDescription: "Fordert Crawler auf, gepostetes Text- oder Bildmaterial usw. nicht in Datensätzen für maschinelles Lernen (Generative bzw. Prediktive AI/KI) zu verwenden. Dies wird durch das Hinzufügen einer \"noai\"-Flag in der HTML-Antwort des jeweiligen Inhalts erreicht. Da diese Flag jedoch ignoriert werden kann, ist eine vollständige Verhinderung hierdurch nicht möglich."
|
preventAiLearningDescription: "Fordert Crawler auf, gepostetes Text- oder Bildmaterial usw. nicht in Datensätzen für maschinelles Lernen (Generative bzw. Prediktive AI/KI) zu verwenden. Dies wird durch das Hinzufügen einer \"noai\"-Flag in der HTML-Antwort des jeweiligen Inhalts erreicht. Da diese Flag jedoch ignoriert werden kann, ist eine vollständige Verhinderung hierdurch nicht möglich."
|
||||||
options: "Optionen"
|
options: "Optionen"
|
||||||
specifyUser: "Spezifischer Benutzer"
|
specifyUser: "Spezifischer Benutzer"
|
||||||
lookupConfirm: "Bist du sicher, dass du das nachschlagen möchtest?"
|
lookupConfirm: "Zustimmen?"
|
||||||
openTagPageConfirm: "Hashtag Seite wirklich öffnen?"
|
openTagPageConfirm: "Hashtag Seite wirklich öffnen?"
|
||||||
specifyHost: "Host"
|
specifyHost: "Host"
|
||||||
failedToPreviewUrl: "Vorschau nicht anzeigbar"
|
failedToPreviewUrl: "Vorschau nicht anzeigbar"
|
||||||
|
@@ -1392,7 +1392,7 @@ _abuseUserReport:
|
|||||||
resolve: "Resolve"
|
resolve: "Resolve"
|
||||||
accept: "Accept"
|
accept: "Accept"
|
||||||
reject: "Reject"
|
reject: "Reject"
|
||||||
resolveTutorial: "If the report's content is legitimate, select \"Accept\" to mark it as resolved.\nIf the report's content is illegitimate, select \"Reject\" to ignore it."
|
resolveTutorial: "If the report is legitimate in content, select \"Accept\" to mark the case as resolved in the affirmative.\nIf the content of the report is not legitimate, select \"Reject\" to mark the case as resolved in the negative."
|
||||||
_delivery:
|
_delivery:
|
||||||
status: "Delivery status"
|
status: "Delivery status"
|
||||||
stop: "Suspended"
|
stop: "Suspended"
|
||||||
@@ -2598,7 +2598,7 @@ _webhookSettings:
|
|||||||
testRemarks: "Click the button to the right of the switch to send a test Webhook with dummy data."
|
testRemarks: "Click the button to the right of the switch to send a test Webhook with dummy data."
|
||||||
_abuseReport:
|
_abuseReport:
|
||||||
_notificationRecipient:
|
_notificationRecipient:
|
||||||
createRecipient: "Add recipient for reports"
|
createRecipient: "Add a recipient for reports"
|
||||||
modifyRecipient: "Edit a recipient for reports"
|
modifyRecipient: "Edit a recipient for reports"
|
||||||
recipientType: "Notification type"
|
recipientType: "Notification type"
|
||||||
_recipientType:
|
_recipientType:
|
||||||
@@ -2828,7 +2828,7 @@ _customEmojisManager:
|
|||||||
confirmImportEmojisTitle: "Import Emojis"
|
confirmImportEmojisTitle: "Import Emojis"
|
||||||
confirmImportEmojisDescription: "Import {count} Emoji(s) received from the remote server. Please pay close attention to the license of the Emoji. Are you sure to continue?"
|
confirmImportEmojisDescription: "Import {count} Emoji(s) received from the remote server. Please pay close attention to the license of the Emoji. Are you sure to continue?"
|
||||||
_local:
|
_local:
|
||||||
tabTitleList: "Registered emojis"
|
tabTitleList: "List of registered Emojis"
|
||||||
tabTitleRegister: "Emoji registration"
|
tabTitleRegister: "Emoji registration"
|
||||||
_list:
|
_list:
|
||||||
emojisNothing: "There are no registered Emojis."
|
emojisNothing: "There are no registered Emojis."
|
||||||
|
@@ -698,7 +698,6 @@ userSaysSomethingAbout: "{name}님이 \"{word}\"를 언급했습니다."
|
|||||||
makeActive: "활성화"
|
makeActive: "활성화"
|
||||||
display: "보기"
|
display: "보기"
|
||||||
copy: "복사"
|
copy: "복사"
|
||||||
copiedToClipboard: "클립보드에 복사되었습니다."
|
|
||||||
metrics: "통계"
|
metrics: "통계"
|
||||||
overview: "요약"
|
overview: "요약"
|
||||||
logs: "로그"
|
logs: "로그"
|
||||||
@@ -1295,7 +1294,7 @@ thereAreNChanges: "{n}건 변경이 있습니다."
|
|||||||
signinWithPasskey: "패스키로 로그인"
|
signinWithPasskey: "패스키로 로그인"
|
||||||
unknownWebAuthnKey: "등록되지 않은 패스키입니다."
|
unknownWebAuthnKey: "등록되지 않은 패스키입니다."
|
||||||
passkeyVerificationFailed: "패스키 검증을 실패했습니다."
|
passkeyVerificationFailed: "패스키 검증을 실패했습니다."
|
||||||
passkeyVerificationSucceededButPasswordlessLoginDisabled: "입력된 패스키는 정상적이나, 비밀번호 없이 로그인 하는 기능이 비활성화 되어있습니다."
|
passkeyVerificationSucceededButPasswordlessLoginDisabled: "패스키를 검증했으나, 비밀번호 없이 로그인하기가 꺼져 있습니다."
|
||||||
messageToFollower: "팔로워에게 보낼 메시지"
|
messageToFollower: "팔로워에게 보낼 메시지"
|
||||||
target: "대상"
|
target: "대상"
|
||||||
testCaptchaWarning: "CAPTCHA를 테스트하기 위한 기능입니다. <strong>실제 환경에서는 사용하지 마세요.</strong>"
|
testCaptchaWarning: "CAPTCHA를 테스트하기 위한 기능입니다. <strong>실제 환경에서는 사용하지 마세요.</strong>"
|
||||||
@@ -1326,40 +1325,21 @@ skip: "건너뛰기"
|
|||||||
restore: "복원"
|
restore: "복원"
|
||||||
syncBetweenDevices: "장치간 동기화"
|
syncBetweenDevices: "장치간 동기화"
|
||||||
preferenceSyncConflictTitle: "서버에 설정값이 존재합니다."
|
preferenceSyncConflictTitle: "서버에 설정값이 존재합니다."
|
||||||
preferenceSyncConflictText: "동기화를 활성화 한 항목의 설정 값은 서버에 저장되지만, 해당 항목은 이미 서버에 설정 값이 저장되어져 있습니다. 어느 쪽의 설정 값을 덮어씌울까요?"
|
|
||||||
preferenceSyncConflictChoiceServer: "서버 설정값"
|
preferenceSyncConflictChoiceServer: "서버 설정값"
|
||||||
preferenceSyncConflictChoiceDevice: "장치 설정값"
|
preferenceSyncConflictChoiceDevice: "장치 설정값"
|
||||||
preferenceSyncConflictChoiceCancel: "동기화 취소"
|
|
||||||
paste: "붙여넣기"
|
paste: "붙여넣기"
|
||||||
emojiPalette: "이모지 팔레트"
|
emojiPalette: "이모지 팔레트"
|
||||||
postForm: "글 입력란"
|
postForm: "글 입력란"
|
||||||
textCount: "문자 수"
|
|
||||||
information: "정보"
|
information: "정보"
|
||||||
_emojiPalette:
|
_emojiPalette:
|
||||||
palettes: "팔레트"
|
palettes: "팔레트"
|
||||||
enableSyncBetweenDevicesForPalettes: "팔레트의 디바이스 간 동기화를 활성화"
|
|
||||||
paletteForMain: "메인으로 사용할 팔레트"
|
paletteForMain: "메인으로 사용할 팔레트"
|
||||||
paletteForReaction: "리액션으로 사용할 팔레트"
|
paletteForReaction: "리액션으로 사용할 팔레트"
|
||||||
_settings:
|
_settings:
|
||||||
driveBanner: "드라이브 관리, 사용량 확인, 파일 업로드에 관한 설정을 합니다."
|
|
||||||
pluginBanner: "플러그인을 사용하면 클라이언트 기능을 확장할 수 있습니다. 플러그인 설치와 개별적인 설정을 합니다."
|
|
||||||
notificationsBanner: "서버에서 받는 알림의 종류 및 범위, 푸시 알림 설정을 합니다."
|
|
||||||
api: "API"
|
api: "API"
|
||||||
webhook: "Webhook"
|
webhook: "Webhook"
|
||||||
serviceConnection: "서비스 연동"
|
serviceConnection: "서비스 연동"
|
||||||
serviceConnectionBanner: "외부 앱, 서비스와 연결하기 위한 액세스 토큰과 웹 훅 관리 설정을 합니다."
|
|
||||||
accountData: "계정 데이터"
|
accountData: "계정 데이터"
|
||||||
accountDataBanner: "계정 데이터의 아카이브를 추출하기/가져오기 하여 관리할 수 있습니다."
|
|
||||||
muteAndBlockBanner: "숨길 컨텐츠의 설정과, 특정 유저의 리액션을 제한하는 설정을 관리합니다."
|
|
||||||
accessibilityBanner: "좀 더 쾌적하게 사용할 수 있도록 클라이언트의 시각 및 움직임에 관한 개인화 설정을 합니다."
|
|
||||||
privacyBanner: "컨텐츠, 계정의 발견 범위, 팔로우 승인제 등의 계정의 프라이버시에 관한 설정을 합니다."
|
|
||||||
securityBanner: "비밀번호, 로그인 방법, OTP, 패스 키 등의 계정의 보안에 관련된 설정을 합니다."
|
|
||||||
preferencesBanner: "취향에 알맞는 클라이언트의 전체적인 동작을 설정합니다."
|
|
||||||
appearanceBanner: "취향에 알맞는 클라이언트의 디스플레이, 표시 방법에 관한 설정을 합니다."
|
|
||||||
soundsBanner: "클라이언트에서 재생할 소리에 대한 설정을 합니다."
|
|
||||||
timelineAndNote: "타임라인과 노트"
|
|
||||||
makeEveryTextElementsSelectable: "모든 텍스트 요소를 선택할 수 있도록 함"
|
|
||||||
makeEveryTextElementsSelectable_description: "활성화 시, 일부 동작에서 사용자의 접근성이 나빠질 수도 있습니다."
|
|
||||||
_preferencesProfile:
|
_preferencesProfile:
|
||||||
profileName: "프로필 이름"
|
profileName: "프로필 이름"
|
||||||
profileNameDescription: "이 디바이스를 식별할 이름을 설정해 주세요."
|
profileNameDescription: "이 디바이스를 식별할 이름을 설정해 주세요."
|
||||||
@@ -1383,7 +1363,6 @@ _accountSettings:
|
|||||||
makeNotesHiddenBefore: "과거 노트 비공개로 전환하기"
|
makeNotesHiddenBefore: "과거 노트 비공개로 전환하기"
|
||||||
makeNotesHiddenBeforeDescription: "이 기능이 활성화되어 있는 동안 설정한 날짜 및 시간보다 과거 또는 설정한 시간이 지난 노트는 본인만 볼 수 있게(비공개로 전환) 됩니다. 비활성화하면 노트의 공개 상태도 원래대로 돌아갑니다."
|
makeNotesHiddenBeforeDescription: "이 기능이 활성화되어 있는 동안 설정한 날짜 및 시간보다 과거 또는 설정한 시간이 지난 노트는 본인만 볼 수 있게(비공개로 전환) 됩니다. 비활성화하면 노트의 공개 상태도 원래대로 돌아갑니다."
|
||||||
mayNotEffectForFederatedNotes: "원격 서버에 연합된 노트에는 효과가 없을 수도 있습니다."
|
mayNotEffectForFederatedNotes: "원격 서버에 연합된 노트에는 효과가 없을 수도 있습니다."
|
||||||
mayNotEffectSomeSituations: "여기서 설정하는 제한은 모더레이션이나 리모트 서버에서 볼 때 등 일부 환경에서는 적용되지 않을 수도 있습니다."
|
|
||||||
notesHavePassedSpecifiedPeriod: "지정한 시간이 경과된 노트"
|
notesHavePassedSpecifiedPeriod: "지정한 시간이 경과된 노트"
|
||||||
notesOlderThanSpecifiedDateAndTime: "지정된 날짜 및 시간 이전의 노트"
|
notesOlderThanSpecifiedDateAndTime: "지정된 날짜 및 시간 이전의 노트"
|
||||||
_abuseUserReport:
|
_abuseUserReport:
|
||||||
@@ -2524,7 +2503,6 @@ _notification:
|
|||||||
achievementEarned: "도전 과제 획득"
|
achievementEarned: "도전 과제 획득"
|
||||||
exportCompleted: "추출을 성공함"
|
exportCompleted: "추출을 성공함"
|
||||||
login: "로그인"
|
login: "로그인"
|
||||||
createToken: "액세스 토큰 만들기"
|
|
||||||
test: "알림 테스트"
|
test: "알림 테스트"
|
||||||
app: "연동된 앱을 통한 알림"
|
app: "연동된 앱을 통한 알림"
|
||||||
_actions:
|
_actions:
|
||||||
@@ -2552,7 +2530,6 @@ _deck:
|
|||||||
useSimpleUiForNonRootPages: "루트 이외의 페이지로 접속한 경우 UI 간략화하기"
|
useSimpleUiForNonRootPages: "루트 이외의 페이지로 접속한 경우 UI 간략화하기"
|
||||||
usedAsMinWidthWhenFlexible: "'폭 자동 조정'이 활성화된 경우 최소 폭으로 사용됩니다"
|
usedAsMinWidthWhenFlexible: "'폭 자동 조정'이 활성화된 경우 최소 폭으로 사용됩니다"
|
||||||
flexible: "폭 자동 조정"
|
flexible: "폭 자동 조정"
|
||||||
enableSyncBetweenDevicesForProfiles: "프로파일 정보의 디바이스 간 동기화를 활성화"
|
|
||||||
_columns:
|
_columns:
|
||||||
main: "메인"
|
main: "메인"
|
||||||
widgets: "위젯"
|
widgets: "위젯"
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"version": "2025.3.2-beta.6",
|
"version": "2025.3.2-beta.9",
|
||||||
"codename": "nasubi",
|
"codename": "nasubi",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@@ -37,17 +37,17 @@
|
|||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@swc/core-android-arm64": "1.3.11",
|
"@swc/core-android-arm64": "1.3.11",
|
||||||
"@swc/core-darwin-arm64": "1.10.16",
|
"@swc/core-darwin-arm64": "1.11.11",
|
||||||
"@swc/core-darwin-x64": "1.10.16",
|
"@swc/core-darwin-x64": "1.11.11",
|
||||||
"@swc/core-freebsd-x64": "1.3.11",
|
"@swc/core-freebsd-x64": "1.3.11",
|
||||||
"@swc/core-linux-arm-gnueabihf": "1.10.16",
|
"@swc/core-linux-arm-gnueabihf": "1.11.11",
|
||||||
"@swc/core-linux-arm64-gnu": "1.10.16",
|
"@swc/core-linux-arm64-gnu": "1.11.11",
|
||||||
"@swc/core-linux-arm64-musl": "1.10.16",
|
"@swc/core-linux-arm64-musl": "1.11.11",
|
||||||
"@swc/core-linux-x64-gnu": "1.10.16",
|
"@swc/core-linux-x64-gnu": "1.11.11",
|
||||||
"@swc/core-linux-x64-musl": "1.10.16",
|
"@swc/core-linux-x64-musl": "1.11.11",
|
||||||
"@swc/core-win32-arm64-msvc": "1.10.16",
|
"@swc/core-win32-arm64-msvc": "1.11.11",
|
||||||
"@swc/core-win32-ia32-msvc": "1.10.16",
|
"@swc/core-win32-ia32-msvc": "1.11.11",
|
||||||
"@swc/core-win32-x64-msvc": "1.10.16",
|
"@swc/core-win32-x64-msvc": "1.11.11",
|
||||||
"@tensorflow/tfjs": "4.22.0",
|
"@tensorflow/tfjs": "4.22.0",
|
||||||
"@tensorflow/tfjs-node": "4.22.0",
|
"@tensorflow/tfjs-node": "4.22.0",
|
||||||
"bufferutil": "4.0.9",
|
"bufferutil": "4.0.9",
|
||||||
@@ -67,23 +67,23 @@
|
|||||||
"utf-8-validate": "6.0.5"
|
"utf-8-validate": "6.0.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "3.749.0",
|
"@aws-sdk/client-s3": "3.772.0",
|
||||||
"@aws-sdk/lib-storage": "3.749.0",
|
"@aws-sdk/lib-storage": "3.772.0",
|
||||||
"@discordapp/twemoji": "15.1.0",
|
"@discordapp/twemoji": "15.1.0",
|
||||||
"@fastify/accepts": "5.0.2",
|
"@fastify/accepts": "5.0.2",
|
||||||
"@fastify/cookie": "11.0.2",
|
"@fastify/cookie": "11.0.2",
|
||||||
"@fastify/cors": "10.0.2",
|
"@fastify/cors": "10.1.0",
|
||||||
"@fastify/express": "4.0.2",
|
"@fastify/express": "4.0.2",
|
||||||
"@fastify/http-proxy": "10.0.2",
|
"@fastify/http-proxy": "10.0.2",
|
||||||
"@fastify/multipart": "9.0.3",
|
"@fastify/multipart": "9.0.3",
|
||||||
"@fastify/static": "8.1.0",
|
"@fastify/static": "8.1.1",
|
||||||
"@fastify/view": "10.0.2",
|
"@fastify/view": "10.0.2",
|
||||||
"@misskey-dev/sharp-read-bmp": "1.2.0",
|
"@misskey-dev/sharp-read-bmp": "1.2.0",
|
||||||
"@misskey-dev/summaly": "5.2.0",
|
"@misskey-dev/summaly": "5.2.0",
|
||||||
"@napi-rs/canvas": "0.1.67",
|
"@napi-rs/canvas": "0.1.68",
|
||||||
"@nestjs/common": "11.0.9",
|
"@nestjs/common": "11.0.12",
|
||||||
"@nestjs/core": "11.0.9",
|
"@nestjs/core": "11.0.12",
|
||||||
"@nestjs/testing": "11.0.9",
|
"@nestjs/testing": "11.0.12",
|
||||||
"@peertube/http-signature": "1.7.0",
|
"@peertube/http-signature": "1.7.0",
|
||||||
"@sentry/node": "8.55.0",
|
"@sentry/node": "8.55.0",
|
||||||
"@sentry/profiling-node": "8.55.0",
|
"@sentry/profiling-node": "8.55.0",
|
||||||
@@ -91,7 +91,7 @@
|
|||||||
"@sinonjs/fake-timers": "11.3.1",
|
"@sinonjs/fake-timers": "11.3.1",
|
||||||
"@smithy/node-http-handler": "2.5.0",
|
"@smithy/node-http-handler": "2.5.0",
|
||||||
"@swc/cli": "0.6.0",
|
"@swc/cli": "0.6.0",
|
||||||
"@swc/core": "1.10.16",
|
"@swc/core": "1.11.11",
|
||||||
"@twemoji/parser": "15.1.1",
|
"@twemoji/parser": "15.1.1",
|
||||||
"accepts": "1.3.8",
|
"accepts": "1.3.8",
|
||||||
"ajv": "8.17.1",
|
"ajv": "8.17.1",
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"blurhash": "2.0.5",
|
"blurhash": "2.0.5",
|
||||||
"body-parser": "1.20.3",
|
"body-parser": "1.20.3",
|
||||||
"bullmq": "5.41.1",
|
"bullmq": "5.44.1",
|
||||||
"cacheable-lookup": "7.0.0",
|
"cacheable-lookup": "7.0.0",
|
||||||
"cbor": "9.0.2",
|
"cbor": "9.0.2",
|
||||||
"chalk": "5.4.1",
|
"chalk": "5.4.1",
|
||||||
@@ -122,7 +122,7 @@
|
|||||||
"hpagent": "1.2.0",
|
"hpagent": "1.2.0",
|
||||||
"htmlescape": "1.1.1",
|
"htmlescape": "1.1.1",
|
||||||
"http-link-header": "1.1.3",
|
"http-link-header": "1.1.3",
|
||||||
"ioredis": "5.5.0",
|
"ioredis": "5.6.0",
|
||||||
"ip-cidr": "4.0.2",
|
"ip-cidr": "4.0.2",
|
||||||
"ipaddr.js": "2.2.0",
|
"ipaddr.js": "2.2.0",
|
||||||
"is-svg": "5.1.0",
|
"is-svg": "5.1.0",
|
||||||
@@ -131,26 +131,26 @@
|
|||||||
"json5": "2.2.3",
|
"json5": "2.2.3",
|
||||||
"jsonld": "8.3.3",
|
"jsonld": "8.3.3",
|
||||||
"jsrsasign": "11.1.0",
|
"jsrsasign": "11.1.0",
|
||||||
"juice": "11.0.0",
|
"juice": "11.0.1",
|
||||||
"meilisearch": "0.48.2",
|
"meilisearch": "0.49.0",
|
||||||
"mfm-js": "0.24.0",
|
"mfm-js": "0.24.0",
|
||||||
"microformats-parser": "2.0.2",
|
"microformats-parser": "2.0.2",
|
||||||
"mime-types": "2.1.35",
|
"mime-types": "2.1.35",
|
||||||
"misskey-js": "workspace:*",
|
"misskey-js": "workspace:*",
|
||||||
"misskey-reversi": "workspace:*",
|
"misskey-reversi": "workspace:*",
|
||||||
"ms": "3.0.0-canary.1",
|
"ms": "3.0.0-canary.1",
|
||||||
"nanoid": "5.1.0",
|
"nanoid": "5.1.5",
|
||||||
"nested-property": "4.0.0",
|
"nested-property": "4.0.0",
|
||||||
"node-fetch": "3.3.2",
|
"node-fetch": "3.3.2",
|
||||||
"nodemailer": "6.10.0",
|
"nodemailer": "6.10.0",
|
||||||
"nsfwjs": "4.2.0",
|
"nsfwjs": "4.2.0",
|
||||||
"oauth": "0.10.0",
|
"oauth": "0.10.2",
|
||||||
"oauth2orize": "1.12.0",
|
"oauth2orize": "1.12.0",
|
||||||
"oauth2orize-pkce": "0.1.2",
|
"oauth2orize-pkce": "0.1.2",
|
||||||
"os-utils": "0.0.14",
|
"os-utils": "0.0.14",
|
||||||
"otpauth": "9.3.6",
|
"otpauth": "9.3.6",
|
||||||
"parse5": "7.2.1",
|
"parse5": "7.2.1",
|
||||||
"pg": "8.13.3",
|
"pg": "8.14.1",
|
||||||
"pkce-challenge": "4.1.0",
|
"pkce-challenge": "4.1.0",
|
||||||
"probe-image-size": "7.2.3",
|
"probe-image-size": "7.2.3",
|
||||||
"promise-limit": "2.7.0",
|
"promise-limit": "2.7.0",
|
||||||
@@ -163,8 +163,8 @@
|
|||||||
"reflect-metadata": "0.2.2",
|
"reflect-metadata": "0.2.2",
|
||||||
"rename": "1.0.4",
|
"rename": "1.0.4",
|
||||||
"rss-parser": "3.13.0",
|
"rss-parser": "3.13.0",
|
||||||
"rxjs": "7.8.1",
|
"rxjs": "7.8.2",
|
||||||
"sanitize-html": "2.14.0",
|
"sanitize-html": "2.15.0",
|
||||||
"secure-json-parse": "3.0.2",
|
"secure-json-parse": "3.0.2",
|
||||||
"sharp": "0.33.5",
|
"sharp": "0.33.5",
|
||||||
"slacc": "0.0.10",
|
"slacc": "0.0.10",
|
||||||
@@ -173,14 +173,14 @@
|
|||||||
"systeminformation": "5.25.11",
|
"systeminformation": "5.25.11",
|
||||||
"tinycolor2": "1.6.0",
|
"tinycolor2": "1.6.0",
|
||||||
"tmp": "0.2.3",
|
"tmp": "0.2.3",
|
||||||
"tsc-alias": "1.8.10",
|
"tsc-alias": "1.8.11",
|
||||||
"tsconfig-paths": "4.2.0",
|
"tsconfig-paths": "4.2.0",
|
||||||
"typeorm": "0.3.20",
|
"typeorm": "0.3.21",
|
||||||
"typescript": "5.7.3",
|
"typescript": "5.8.2",
|
||||||
"ulid": "2.3.0",
|
"ulid": "2.4.0",
|
||||||
"vary": "1.1.2",
|
"vary": "1.1.2",
|
||||||
"web-push": "3.6.7",
|
"web-push": "3.6.7",
|
||||||
"ws": "8.18.0",
|
"ws": "8.18.1",
|
||||||
"xev": "3.0.2"
|
"xev": "3.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -204,7 +204,7 @@
|
|||||||
"@types/jsrsasign": "10.5.15",
|
"@types/jsrsasign": "10.5.15",
|
||||||
"@types/mime-types": "2.1.4",
|
"@types/mime-types": "2.1.4",
|
||||||
"@types/ms": "0.7.34",
|
"@types/ms": "0.7.34",
|
||||||
"@types/node": "22.13.4",
|
"@types/node": "22.13.10",
|
||||||
"@types/nodemailer": "6.4.17",
|
"@types/nodemailer": "6.4.17",
|
||||||
"@types/oauth": "0.9.6",
|
"@types/oauth": "0.9.6",
|
||||||
"@types/oauth2orize": "1.11.5",
|
"@types/oauth2orize": "1.11.5",
|
||||||
@@ -223,9 +223,9 @@
|
|||||||
"@types/tmp": "0.2.6",
|
"@types/tmp": "0.2.6",
|
||||||
"@types/vary": "1.1.3",
|
"@types/vary": "1.1.3",
|
||||||
"@types/web-push": "3.6.4",
|
"@types/web-push": "3.6.4",
|
||||||
"@types/ws": "8.5.14",
|
"@types/ws": "8.18.0",
|
||||||
"@typescript-eslint/eslint-plugin": "8.24.0",
|
"@typescript-eslint/eslint-plugin": "8.27.0",
|
||||||
"@typescript-eslint/parser": "8.24.0",
|
"@typescript-eslint/parser": "8.27.0",
|
||||||
"aws-sdk-client-mock": "4.1.0",
|
"aws-sdk-client-mock": "4.1.0",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"eslint-plugin-import": "2.31.0",
|
"eslint-plugin-import": "2.31.0",
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as fs from 'node:fs/promises';
|
import * as fs from 'node:fs/promises';
|
||||||
|
import { WritableStream } from 'node:stream/web';
|
||||||
import type { PathLike } from 'node:fs';
|
import type { PathLike } from 'node:fs';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -391,10 +391,10 @@ export class ApiCallService implements OnApplicationShutdown {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ep.meta.requireRolePolicy != null && (this.meta.rootUserId !== user!.id)) {
|
if (ep.meta.requiredRolePolicy != null && (this.meta.rootUserId !== user!.id)) {
|
||||||
const myRoles = await this.roleService.getUserRoles(user!.id);
|
const myRoles = await this.roleService.getUserRoles(user!.id);
|
||||||
const policies = await this.roleService.getUserPolicies(user!.id);
|
const policies = await this.roleService.getUserPolicies(user!.id);
|
||||||
if (!policies[ep.meta.requireRolePolicy] && !myRoles.some(r => r.isAdministrator)) {
|
if (!policies[ep.meta.requiredRolePolicy] && !myRoles.some(r => r.isAdministrator)) {
|
||||||
throw new ApiError({
|
throw new ApiError({
|
||||||
message: 'You are not assigned to a required role.',
|
message: 'You are not assigned to a required role.',
|
||||||
code: 'ROLE_PERMISSION_DENIED',
|
code: 'ROLE_PERMISSION_DENIED',
|
||||||
|
@@ -39,7 +39,7 @@ interface IEndpointMetaBase {
|
|||||||
*/
|
*/
|
||||||
readonly requireAdmin?: boolean;
|
readonly requireAdmin?: boolean;
|
||||||
|
|
||||||
readonly requireRolePolicy?: KeyOf<'RolePolicies'>;
|
readonly requiredRolePolicy?: KeyOf<'RolePolicies'>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 引っ越し済みのユーザーによるリクエストを禁止するか
|
* 引っ越し済みのユーザーによるリクエストを禁止するか
|
||||||
|
@@ -12,7 +12,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canManageAvatarDecorations',
|
requiredRolePolicy: 'canManageAvatarDecorations',
|
||||||
kind: 'write:admin:avatar-decorations',
|
kind: 'write:admin:avatar-decorations',
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
|
@@ -13,7 +13,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canManageAvatarDecorations',
|
requiredRolePolicy: 'canManageAvatarDecorations',
|
||||||
kind: 'write:admin:avatar-decorations',
|
kind: 'write:admin:avatar-decorations',
|
||||||
errors: {
|
errors: {
|
||||||
},
|
},
|
||||||
|
@@ -13,7 +13,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canManageAvatarDecorations',
|
requiredRolePolicy: 'canManageAvatarDecorations',
|
||||||
kind: 'read:admin:avatar-decorations',
|
kind: 'read:admin:avatar-decorations',
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
|
@@ -13,7 +13,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canManageAvatarDecorations',
|
requiredRolePolicy: 'canManageAvatarDecorations',
|
||||||
kind: 'write:admin:avatar-decorations',
|
kind: 'write:admin:avatar-decorations',
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
|
@@ -11,7 +11,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canManageCustomEmojis',
|
requiredRolePolicy: 'canManageCustomEmojis',
|
||||||
kind: 'write:admin:emoji',
|
kind: 'write:admin:emoji',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
@@ -16,7 +16,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canManageCustomEmojis',
|
requiredRolePolicy: 'canManageCustomEmojis',
|
||||||
kind: 'write:admin:emoji',
|
kind: 'write:admin:emoji',
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
|
@@ -17,7 +17,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canManageCustomEmojis',
|
requiredRolePolicy: 'canManageCustomEmojis',
|
||||||
kind: 'write:admin:emoji',
|
kind: 'write:admin:emoji',
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
|
@@ -11,7 +11,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canManageCustomEmojis',
|
requiredRolePolicy: 'canManageCustomEmojis',
|
||||||
kind: 'write:admin:emoji',
|
kind: 'write:admin:emoji',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
@@ -11,7 +11,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canManageCustomEmojis',
|
requiredRolePolicy: 'canManageCustomEmojis',
|
||||||
kind: 'write:admin:emoji',
|
kind: 'write:admin:emoji',
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
|
@@ -10,7 +10,7 @@ import { QueueService } from '@/core/QueueService.js';
|
|||||||
export const meta = {
|
export const meta = {
|
||||||
secure: true,
|
secure: true,
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canManageCustomEmojis',
|
requiredRolePolicy: 'canManageCustomEmojis',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const paramDef = {
|
export const paramDef = {
|
||||||
|
@@ -16,7 +16,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canManageCustomEmojis',
|
requiredRolePolicy: 'canManageCustomEmojis',
|
||||||
kind: 'read:admin:emoji',
|
kind: 'read:admin:emoji',
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
|
@@ -16,7 +16,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canManageCustomEmojis',
|
requiredRolePolicy: 'canManageCustomEmojis',
|
||||||
kind: 'read:admin:emoji',
|
kind: 'read:admin:emoji',
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
|
@@ -11,7 +11,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canManageCustomEmojis',
|
requiredRolePolicy: 'canManageCustomEmojis',
|
||||||
kind: 'write:admin:emoji',
|
kind: 'write:admin:emoji',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
@@ -11,7 +11,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canManageCustomEmojis',
|
requiredRolePolicy: 'canManageCustomEmojis',
|
||||||
kind: 'write:admin:emoji',
|
kind: 'write:admin:emoji',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
@@ -11,7 +11,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canManageCustomEmojis',
|
requiredRolePolicy: 'canManageCustomEmojis',
|
||||||
kind: 'write:admin:emoji',
|
kind: 'write:admin:emoji',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
@@ -11,7 +11,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canManageCustomEmojis',
|
requiredRolePolicy: 'canManageCustomEmojis',
|
||||||
kind: 'write:admin:emoji',
|
kind: 'write:admin:emoji',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
@@ -14,7 +14,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canManageCustomEmojis',
|
requiredRolePolicy: 'canManageCustomEmojis',
|
||||||
kind: 'write:admin:emoji',
|
kind: 'write:admin:emoji',
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
|
@@ -16,7 +16,7 @@ import { ApiError } from '../../error.js';
|
|||||||
export const meta = {
|
export const meta = {
|
||||||
secure: true,
|
secure: true,
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canImportAntennas',
|
requiredRolePolicy: 'canImportAntennas',
|
||||||
prohibitMoved: true,
|
prohibitMoved: true,
|
||||||
|
|
||||||
limit: {
|
limit: {
|
||||||
|
@@ -15,7 +15,7 @@ import { ApiError } from '../../error.js';
|
|||||||
export const meta = {
|
export const meta = {
|
||||||
secure: true,
|
secure: true,
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canImportBlocking',
|
requiredRolePolicy: 'canImportBlocking',
|
||||||
prohibitMoved: true,
|
prohibitMoved: true,
|
||||||
|
|
||||||
limit: {
|
limit: {
|
||||||
|
@@ -15,7 +15,7 @@ import { ApiError } from '../../error.js';
|
|||||||
export const meta = {
|
export const meta = {
|
||||||
secure: true,
|
secure: true,
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canImportFollowing',
|
requiredRolePolicy: 'canImportFollowing',
|
||||||
prohibitMoved: true,
|
prohibitMoved: true,
|
||||||
limit: {
|
limit: {
|
||||||
duration: ms('1hour'),
|
duration: ms('1hour'),
|
||||||
|
@@ -15,7 +15,7 @@ import { ApiError } from '../../error.js';
|
|||||||
export const meta = {
|
export const meta = {
|
||||||
secure: true,
|
secure: true,
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canImportMuting',
|
requiredRolePolicy: 'canImportMuting',
|
||||||
prohibitMoved: true,
|
prohibitMoved: true,
|
||||||
|
|
||||||
limit: {
|
limit: {
|
||||||
|
@@ -15,7 +15,7 @@ import { ApiError } from '../../error.js';
|
|||||||
export const meta = {
|
export const meta = {
|
||||||
secure: true,
|
secure: true,
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canImportUserLists',
|
requiredRolePolicy: 'canImportUserLists',
|
||||||
prohibitMoved: true,
|
prohibitMoved: true,
|
||||||
limit: {
|
limit: {
|
||||||
duration: ms('1hour'),
|
duration: ms('1hour'),
|
||||||
|
@@ -18,7 +18,7 @@ export const meta = {
|
|||||||
tags: ['meta'],
|
tags: ['meta'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canInvite',
|
requiredRolePolicy: 'canInvite',
|
||||||
kind: 'write:invite-codes',
|
kind: 'write:invite-codes',
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
|
@@ -14,7 +14,7 @@ export const meta = {
|
|||||||
tags: ['meta'],
|
tags: ['meta'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canInvite',
|
requiredRolePolicy: 'canInvite',
|
||||||
kind: 'write:invite-codes',
|
kind: 'write:invite-codes',
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
|
@@ -15,7 +15,7 @@ export const meta = {
|
|||||||
tags: ['meta'],
|
tags: ['meta'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canInvite',
|
requiredRolePolicy: 'canInvite',
|
||||||
kind: 'read:invite-codes',
|
kind: 'read:invite-codes',
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
|
@@ -14,7 +14,7 @@ export const meta = {
|
|||||||
tags: ['meta'],
|
tags: ['meta'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canInvite',
|
requiredRolePolicy: 'canInvite',
|
||||||
kind: 'read:invite-codes',
|
kind: 'read:invite-codes',
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
|
@@ -12,7 +12,7 @@ export const meta = {
|
|||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
requireRolePolicy: 'canManageCustomEmojis',
|
requiredRolePolicy: 'canManageCustomEmojis',
|
||||||
kind: 'read:admin:emoji',
|
kind: 'read:admin:emoji',
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
"@rollup/pluginutils": "5.1.4",
|
"@rollup/pluginutils": "5.1.4",
|
||||||
"@tabler/icons-webfont": "3.31.0",
|
"@tabler/icons-webfont": "3.31.0",
|
||||||
"@twemoji/parser": "15.1.1",
|
"@twemoji/parser": "15.1.1",
|
||||||
"@vitejs/plugin-vue": "5.2.1",
|
"@vitejs/plugin-vue": "5.2.3",
|
||||||
"@vue/compiler-sfc": "3.5.13",
|
"@vue/compiler-sfc": "3.5.13",
|
||||||
"astring": "1.9.0",
|
"astring": "1.9.0",
|
||||||
"buraha": "0.0.1",
|
"buraha": "0.0.1",
|
||||||
@@ -25,16 +25,16 @@
|
|||||||
"misskey-js": "workspace:*",
|
"misskey-js": "workspace:*",
|
||||||
"frontend-shared": "workspace:*",
|
"frontend-shared": "workspace:*",
|
||||||
"punycode.js": "2.3.1",
|
"punycode.js": "2.3.1",
|
||||||
"rollup": "4.34.9",
|
"rollup": "4.36.0",
|
||||||
"sass": "1.85.1",
|
"sass": "1.86.0",
|
||||||
"shiki": "3.1.0",
|
"shiki": "3.2.1",
|
||||||
"tinycolor2": "1.6.0",
|
"tinycolor2": "1.6.0",
|
||||||
"tsc-alias": "1.8.11",
|
"tsc-alias": "1.8.11",
|
||||||
"tsconfig-paths": "4.2.0",
|
"tsconfig-paths": "4.2.0",
|
||||||
"typescript": "5.8.2",
|
"typescript": "5.8.2",
|
||||||
"uuid": "11.1.0",
|
"uuid": "11.1.0",
|
||||||
"json5": "2.2.3",
|
"json5": "2.2.3",
|
||||||
"vite": "6.2.1",
|
"vite": "6.2.2",
|
||||||
"vue": "3.5.13"
|
"vue": "3.5.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -42,26 +42,26 @@
|
|||||||
"@testing-library/vue": "8.1.0",
|
"@testing-library/vue": "8.1.0",
|
||||||
"@types/estree": "1.0.6",
|
"@types/estree": "1.0.6",
|
||||||
"@types/micromatch": "4.0.9",
|
"@types/micromatch": "4.0.9",
|
||||||
"@types/node": "22.13.9",
|
"@types/node": "22.13.11",
|
||||||
"@types/punycode.js": "npm:@types/punycode@2.1.4",
|
"@types/punycode.js": "npm:@types/punycode@2.1.4",
|
||||||
"@types/tinycolor2": "1.4.6",
|
"@types/tinycolor2": "1.4.6",
|
||||||
"@types/ws": "8.18.0",
|
"@types/ws": "8.18.0",
|
||||||
"@typescript-eslint/eslint-plugin": "8.26.0",
|
"@typescript-eslint/eslint-plugin": "8.27.0",
|
||||||
"@typescript-eslint/parser": "8.26.0",
|
"@typescript-eslint/parser": "8.27.0",
|
||||||
"@vitest/coverage-v8": "3.0.8",
|
"@vitest/coverage-v8": "3.0.9",
|
||||||
"@vue/runtime-core": "3.5.13",
|
"@vue/runtime-core": "3.5.13",
|
||||||
"acorn": "8.14.1",
|
"acorn": "8.14.1",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"eslint-plugin-import": "2.31.0",
|
"eslint-plugin-import": "2.31.0",
|
||||||
"eslint-plugin-vue": "10.0.0",
|
"eslint-plugin-vue": "10.0.0",
|
||||||
"fast-glob": "3.3.3",
|
"fast-glob": "3.3.3",
|
||||||
"happy-dom": "17.3.0",
|
"happy-dom": "17.4.4",
|
||||||
"intersection-observer": "0.12.2",
|
"intersection-observer": "0.12.2",
|
||||||
"micromatch": "4.0.8",
|
"micromatch": "4.0.8",
|
||||||
"msw": "2.7.3",
|
"msw": "2.7.3",
|
||||||
"nodemon": "3.1.9",
|
"nodemon": "3.1.9",
|
||||||
"prettier": "3.5.3",
|
"prettier": "3.5.3",
|
||||||
"start-server-and-test": "2.0.10",
|
"start-server-and-test": "2.0.11",
|
||||||
"vite-plugin-turbosnap": "1.0.3",
|
"vite-plugin-turbosnap": "1.0.3",
|
||||||
"vue-component-type-helpers": "2.2.8",
|
"vue-component-type-helpers": "2.2.8",
|
||||||
"vue-eslint-parser": "10.1.1",
|
"vue-eslint-parser": "10.1.1",
|
||||||
|
@@ -109,12 +109,6 @@ export const ROLE_POLICIES = [
|
|||||||
'canImportUserLists',
|
'canImportUserLists',
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
// なんか動かない
|
|
||||||
//export const CURRENT_STICKY_TOP = Symbol('CURRENT_STICKY_TOP');
|
|
||||||
//export const CURRENT_STICKY_BOTTOM = Symbol('CURRENT_STICKY_BOTTOM');
|
|
||||||
export const CURRENT_STICKY_TOP = 'CURRENT_STICKY_TOP';
|
|
||||||
export const CURRENT_STICKY_BOTTOM = 'CURRENT_STICKY_BOTTOM';
|
|
||||||
|
|
||||||
export const DEFAULT_SERVER_ERROR_IMAGE_URL = 'https://xn--931a.moe/assets/error.jpg';
|
export const DEFAULT_SERVER_ERROR_IMAGE_URL = 'https://xn--931a.moe/assets/error.jpg';
|
||||||
export const DEFAULT_NOT_FOUND_IMAGE_URL = 'https://xn--931a.moe/assets/not-found.jpg';
|
export const DEFAULT_NOT_FOUND_IMAGE_URL = 'https://xn--931a.moe/assets/not-found.jpg';
|
||||||
export const DEFAULT_INFO_IMAGE_URL = 'https://xn--931a.moe/assets/info.jpg';
|
export const DEFAULT_INFO_IMAGE_URL = 'https://xn--931a.moe/assets/info.jpg';
|
||||||
|
@@ -21,10 +21,10 @@
|
|||||||
"lint": "pnpm typecheck && pnpm eslint"
|
"lint": "pnpm typecheck && pnpm eslint"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "22.13.9",
|
"@types/node": "22.13.11",
|
||||||
"@typescript-eslint/eslint-plugin": "8.26.0",
|
"@typescript-eslint/eslint-plugin": "8.27.0",
|
||||||
"@typescript-eslint/parser": "8.26.0",
|
"@typescript-eslint/parser": "8.27.0",
|
||||||
"esbuild": "0.25.0",
|
"esbuild": "0.25.1",
|
||||||
"eslint-plugin-vue": "10.0.0",
|
"eslint-plugin-vue": "10.0.0",
|
||||||
"nodemon": "3.1.9",
|
"nodemon": "3.1.9",
|
||||||
"typescript": "5.8.2",
|
"typescript": "5.8.2",
|
||||||
|
@@ -131,7 +131,7 @@ export function imageDataUrl(options?: {
|
|||||||
alpha?: number,
|
alpha?: number,
|
||||||
}
|
}
|
||||||
}, seed?: string): string {
|
}, seed?: string): string {
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = window.document.createElement('canvas');
|
||||||
canvas.width = options?.size?.width ?? 100;
|
canvas.width = options?.size?.width ?? 100;
|
||||||
canvas.height = options?.size?.height ?? 100;
|
canvas.height = options?.size?.height ?? 100;
|
||||||
|
|
||||||
|
@@ -23,9 +23,9 @@ let misskeyOS = null;
|
|||||||
|
|
||||||
function loadTheme(applyTheme: typeof import('../src/theme')['applyTheme']) {
|
function loadTheme(applyTheme: typeof import('../src/theme')['applyTheme']) {
|
||||||
unobserve();
|
unobserve();
|
||||||
const theme = themes[document.documentElement.dataset.misskeyTheme];
|
const theme = themes[window.document.documentElement.dataset.misskeyTheme];
|
||||||
if (theme) {
|
if (theme) {
|
||||||
applyTheme(themes[document.documentElement.dataset.misskeyTheme]);
|
applyTheme(themes[window.document.documentElement.dataset.misskeyTheme]);
|
||||||
} else {
|
} else {
|
||||||
applyTheme(themes['l-light']);
|
applyTheme(themes['l-light']);
|
||||||
}
|
}
|
||||||
@@ -42,7 +42,7 @@ function loadTheme(applyTheme: typeof import('../src/theme')['applyTheme']) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
observer.observe(document.documentElement, {
|
observer.observe(window.document.documentElement, {
|
||||||
attributes: true,
|
attributes: true,
|
||||||
attributeFilter: ['data-misskey-theme'],
|
attributeFilter: ['data-misskey-theme'],
|
||||||
});
|
});
|
||||||
|
@@ -56,7 +56,9 @@ export default [
|
|||||||
// open ... window.openと衝突 or 紛らわしい
|
// open ... window.openと衝突 or 紛らわしい
|
||||||
// fetch ... window.fetchと衝突 or 紛らわしい
|
// fetch ... window.fetchと衝突 or 紛らわしい
|
||||||
// location ... window.locationと衝突 or 紛らわしい
|
// location ... window.locationと衝突 or 紛らわしい
|
||||||
'id-denylist': ['warn', 'window', 'e', 'close', 'open', 'fetch', 'location'],
|
// document ... window.documentと衝突 or 紛らわしい
|
||||||
|
// history ... window.historyと衝突 or 紛らわしい
|
||||||
|
'id-denylist': ['warn', 'window', 'e', 'close', 'open', 'fetch', 'location', 'document', 'history'],
|
||||||
'no-restricted-globals': [
|
'no-restricted-globals': [
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
@@ -75,10 +77,18 @@ export default [
|
|||||||
'name': 'location',
|
'name': 'location',
|
||||||
'message': 'Use `window.location`.',
|
'message': 'Use `window.location`.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'name': 'document',
|
||||||
|
'message': 'Use `window.document`.',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
'name': 'history',
|
'name': 'history',
|
||||||
'message': 'Use `window.history`.',
|
'message': 'Use `window.history`.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'name': 'name',
|
||||||
|
'message': 'Use `window.name`. もしくは name という変数名を定義し忘れている',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
'no-shadow': ['warn'],
|
'no-shadow': ['warn'],
|
||||||
'vue/attributes-order': ['error', {
|
'vue/attributes-order': ['error', {
|
||||||
|
@@ -28,7 +28,7 @@
|
|||||||
"@syuilo/aiscript": "0.19.0",
|
"@syuilo/aiscript": "0.19.0",
|
||||||
"@tabler/icons-webfont": "3.31.0",
|
"@tabler/icons-webfont": "3.31.0",
|
||||||
"@twemoji/parser": "15.1.1",
|
"@twemoji/parser": "15.1.1",
|
||||||
"@vitejs/plugin-vue": "5.2.1",
|
"@vitejs/plugin-vue": "5.2.3",
|
||||||
"@vue/compiler-sfc": "3.5.13",
|
"@vue/compiler-sfc": "3.5.13",
|
||||||
"aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.15",
|
"aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.15",
|
||||||
"analytics": "0.8.16",
|
"analytics": "0.8.16",
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
"canvas-confetti": "1.9.3",
|
"canvas-confetti": "1.9.3",
|
||||||
"chart.js": "4.4.8",
|
"chart.js": "4.4.8",
|
||||||
"chartjs-adapter-date-fns": "3.0.0",
|
"chartjs-adapter-date-fns": "3.0.0",
|
||||||
"chartjs-chart-matrix": "2.0.1",
|
"chartjs-chart-matrix": "2.1.1",
|
||||||
"chartjs-plugin-gradient": "0.6.1",
|
"chartjs-plugin-gradient": "0.6.1",
|
||||||
"chartjs-plugin-zoom": "2.2.0",
|
"chartjs-plugin-zoom": "2.2.0",
|
||||||
"chromatic": "11.27.0",
|
"chromatic": "11.27.0",
|
||||||
@@ -60,10 +60,10 @@
|
|||||||
"misskey-reversi": "workspace:*",
|
"misskey-reversi": "workspace:*",
|
||||||
"photoswipe": "5.4.4",
|
"photoswipe": "5.4.4",
|
||||||
"punycode.js": "2.3.1",
|
"punycode.js": "2.3.1",
|
||||||
"rollup": "4.34.9",
|
"rollup": "4.36.0",
|
||||||
"sanitize-html": "2.14.0",
|
"sanitize-html": "2.15.0",
|
||||||
"sass": "1.85.1",
|
"sass": "1.86.0",
|
||||||
"shiki": "3.1.0",
|
"shiki": "3.2.1",
|
||||||
"strict-event-emitter-types": "2.0.0",
|
"strict-event-emitter-types": "2.0.0",
|
||||||
"textarea-caret": "3.1.0",
|
"textarea-caret": "3.1.0",
|
||||||
"three": "0.174.0",
|
"three": "0.174.0",
|
||||||
@@ -74,54 +74,54 @@
|
|||||||
"typescript": "5.8.2",
|
"typescript": "5.8.2",
|
||||||
"uuid": "11.1.0",
|
"uuid": "11.1.0",
|
||||||
"v-code-diff": "1.13.1",
|
"v-code-diff": "1.13.1",
|
||||||
"vite": "6.2.1",
|
"vite": "6.2.2",
|
||||||
"vue": "3.5.13",
|
"vue": "3.5.13",
|
||||||
"vuedraggable": "next",
|
"vuedraggable": "next",
|
||||||
"wanakana": "5.3.1"
|
"wanakana": "5.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@misskey-dev/summaly": "5.2.0",
|
"@misskey-dev/summaly": "5.2.0",
|
||||||
"@storybook/addon-actions": "8.6.4",
|
"@storybook/addon-actions": "8.6.7",
|
||||||
"@storybook/addon-essentials": "8.6.4",
|
"@storybook/addon-essentials": "8.6.7",
|
||||||
"@storybook/addon-interactions": "8.6.4",
|
"@storybook/addon-interactions": "8.6.7",
|
||||||
"@storybook/addon-links": "8.6.4",
|
"@storybook/addon-links": "8.6.7",
|
||||||
"@storybook/addon-mdx-gfm": "8.6.4",
|
"@storybook/addon-mdx-gfm": "8.6.7",
|
||||||
"@storybook/addon-storysource": "8.6.4",
|
"@storybook/addon-storysource": "8.6.7",
|
||||||
"@storybook/blocks": "8.6.4",
|
"@storybook/blocks": "8.6.7",
|
||||||
"@storybook/components": "8.6.4",
|
"@storybook/components": "8.6.7",
|
||||||
"@storybook/core-events": "8.6.4",
|
"@storybook/core-events": "8.6.7",
|
||||||
"@storybook/manager-api": "8.6.4",
|
"@storybook/manager-api": "8.6.7",
|
||||||
"@storybook/preview-api": "8.6.4",
|
"@storybook/preview-api": "8.6.7",
|
||||||
"@storybook/react": "8.6.4",
|
"@storybook/react": "8.6.7",
|
||||||
"@storybook/react-vite": "8.6.4",
|
"@storybook/react-vite": "8.6.7",
|
||||||
"@storybook/test": "8.6.4",
|
"@storybook/test": "8.6.7",
|
||||||
"@storybook/theming": "8.6.4",
|
"@storybook/theming": "8.6.7",
|
||||||
"@storybook/types": "8.6.4",
|
"@storybook/types": "8.6.7",
|
||||||
"@storybook/vue3": "8.6.4",
|
"@storybook/vue3": "8.6.7",
|
||||||
"@storybook/vue3-vite": "8.6.4",
|
"@storybook/vue3-vite": "8.6.7",
|
||||||
"@testing-library/vue": "8.1.0",
|
"@testing-library/vue": "8.1.0",
|
||||||
"@types/canvas-confetti": "1.9.0",
|
"@types/canvas-confetti": "1.9.0",
|
||||||
"@types/estree": "1.0.6",
|
"@types/estree": "1.0.6",
|
||||||
"@types/matter-js": "0.19.8",
|
"@types/matter-js": "0.19.8",
|
||||||
"@types/micromatch": "4.0.9",
|
"@types/micromatch": "4.0.9",
|
||||||
"@types/node": "22.13.9",
|
"@types/node": "22.13.11",
|
||||||
"@types/punycode.js": "npm:@types/punycode@2.1.4",
|
"@types/punycode.js": "npm:@types/punycode@2.1.4",
|
||||||
"@types/sanitize-html": "2.13.0",
|
"@types/sanitize-html": "2.13.0",
|
||||||
"@types/seedrandom": "3.0.8",
|
"@types/seedrandom": "3.0.8",
|
||||||
"@types/throttle-debounce": "5.0.2",
|
"@types/throttle-debounce": "5.0.2",
|
||||||
"@types/tinycolor2": "1.4.6",
|
"@types/tinycolor2": "1.4.6",
|
||||||
"@types/ws": "8.18.0",
|
"@types/ws": "8.18.0",
|
||||||
"@typescript-eslint/eslint-plugin": "8.26.0",
|
"@typescript-eslint/eslint-plugin": "8.27.0",
|
||||||
"@typescript-eslint/parser": "8.26.0",
|
"@typescript-eslint/parser": "8.27.0",
|
||||||
"@vitest/coverage-v8": "3.0.8",
|
"@vitest/coverage-v8": "3.0.9",
|
||||||
"@vue/runtime-core": "3.5.13",
|
"@vue/runtime-core": "3.5.13",
|
||||||
"acorn": "8.14.1",
|
"acorn": "8.14.1",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"cypress": "14.1.0",
|
"cypress": "14.2.0",
|
||||||
"eslint-plugin-import": "2.31.0",
|
"eslint-plugin-import": "2.31.0",
|
||||||
"eslint-plugin-vue": "10.0.0",
|
"eslint-plugin-vue": "10.0.0",
|
||||||
"fast-glob": "3.3.3",
|
"fast-glob": "3.3.3",
|
||||||
"happy-dom": "17.3.0",
|
"happy-dom": "17.4.4",
|
||||||
"intersection-observer": "0.12.2",
|
"intersection-observer": "0.12.2",
|
||||||
"micromatch": "4.0.8",
|
"micromatch": "4.0.8",
|
||||||
"msw": "2.7.3",
|
"msw": "2.7.3",
|
||||||
@@ -131,12 +131,12 @@
|
|||||||
"react": "19.0.0",
|
"react": "19.0.0",
|
||||||
"react-dom": "19.0.0",
|
"react-dom": "19.0.0",
|
||||||
"seedrandom": "3.0.5",
|
"seedrandom": "3.0.5",
|
||||||
"start-server-and-test": "2.0.10",
|
"start-server-and-test": "2.0.11",
|
||||||
"storybook": "8.6.4",
|
"storybook": "8.6.7",
|
||||||
"storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme",
|
"storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme",
|
||||||
"vite-node": "3.0.8",
|
"vite-node": "3.0.9",
|
||||||
"vite-plugin-turbosnap": "1.0.3",
|
"vite-plugin-turbosnap": "1.0.3",
|
||||||
"vitest": "3.0.8",
|
"vitest": "3.0.9",
|
||||||
"vitest-fetch-mock": "0.4.5",
|
"vitest-fetch-mock": "0.4.5",
|
||||||
"vue-component-type-helpers": "2.2.8",
|
"vue-component-type-helpers": "2.2.8",
|
||||||
"vue-eslint-parser": "10.1.1",
|
"vue-eslint-parser": "10.1.1",
|
||||||
|
@@ -14,7 +14,7 @@ import { subBoot } from '@/boot/sub-boot.js';
|
|||||||
|
|
||||||
const subBootPaths = ['/share', '/auth', '/miauth', '/oauth', '/signup-complete', '/install-extensions'];
|
const subBootPaths = ['/share', '/auth', '/miauth', '/oauth', '/signup-complete', '/install-extensions'];
|
||||||
|
|
||||||
if (subBootPaths.some(i => location.pathname === i || location.pathname.startsWith(i + '/'))) {
|
if (subBootPaths.some(i => window.location.pathname === i || window.location.pathname.startsWith(i + '/'))) {
|
||||||
subBoot();
|
subBoot();
|
||||||
} else {
|
} else {
|
||||||
mainBoot();
|
mainBoot();
|
||||||
|
@@ -191,7 +191,7 @@ export async function login(token: AccountWithToken['token'], redirect?: string)
|
|||||||
// 他のタブは再読み込みするだけ
|
// 他のタブは再読み込みするだけ
|
||||||
reloadChannel.postMessage(null);
|
reloadChannel.postMessage(null);
|
||||||
// このページはredirectで指定された先に移動
|
// このページはredirectで指定された先に移動
|
||||||
location.href = redirect;
|
window.location.href = redirect;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -95,28 +95,28 @@ export async function common(createVue: () => App<Element>) {
|
|||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
// タッチデバイスでCSSの:hoverを機能させる
|
// タッチデバイスでCSSの:hoverを機能させる
|
||||||
document.addEventListener('touchend', () => {}, { passive: true });
|
window.document.addEventListener('touchend', () => {}, { passive: true });
|
||||||
|
|
||||||
// URLに#pswpを含む場合は取り除く
|
// URLに#pswpを含む場合は取り除く
|
||||||
if (location.hash === '#pswp') {
|
if (window.location.hash === '#pswp') {
|
||||||
history.replaceState(null, '', location.href.replace('#pswp', ''));
|
window.history.replaceState(null, '', window.location.href.replace('#pswp', ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 一斉リロード
|
// 一斉リロード
|
||||||
reloadChannel.addEventListener('message', path => {
|
reloadChannel.addEventListener('message', path => {
|
||||||
if (path !== null) location.href = path;
|
if (path !== null) window.location.href = path;
|
||||||
else location.reload();
|
else window.location.reload();
|
||||||
});
|
});
|
||||||
|
|
||||||
// If mobile, insert the viewport meta tag
|
// If mobile, insert the viewport meta tag
|
||||||
if (['smartphone', 'tablet'].includes(deviceKind)) {
|
if (['smartphone', 'tablet'].includes(deviceKind)) {
|
||||||
const viewport = document.getElementsByName('viewport').item(0);
|
const viewport = window.document.getElementsByName('viewport').item(0);
|
||||||
viewport.setAttribute('content',
|
viewport.setAttribute('content',
|
||||||
`${viewport.getAttribute('content')}, minimum-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover`);
|
`${viewport.getAttribute('content')}, minimum-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover`);
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region Set lang attr
|
//#region Set lang attr
|
||||||
const html = document.documentElement;
|
const html = window.document.documentElement;
|
||||||
html.setAttribute('lang', lang);
|
html.setAttribute('lang', lang);
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
@@ -130,11 +130,11 @@ export async function common(createVue: () => App<Element>) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
//#region loginId
|
//#region loginId
|
||||||
const params = new URLSearchParams(location.search);
|
const params = new URLSearchParams(window.location.search);
|
||||||
const loginId = params.get('loginId');
|
const loginId = params.get('loginId');
|
||||||
|
|
||||||
if (loginId) {
|
if (loginId) {
|
||||||
const target = getUrlWithoutLoginId(location.href);
|
const target = getUrlWithoutLoginId(window.location.href);
|
||||||
|
|
||||||
if (!$i || $i.id !== loginId) {
|
if (!$i || $i.id !== loginId) {
|
||||||
const account = await getAccountFromId(loginId);
|
const account = await getAccountFromId(loginId);
|
||||||
@@ -143,7 +143,7 @@ export async function common(createVue: () => App<Element>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
history.replaceState({ misskey: 'loginId' }, '', target);
|
window.history.replaceState({ misskey: 'loginId' }, '', target);
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ export async function common(createVue: () => App<Element>) {
|
|||||||
);
|
);
|
||||||
}, { immediate: miLocalStorage.getItem('theme') == null });
|
}, { immediate: miLocalStorage.getItem('theme') == null });
|
||||||
|
|
||||||
document.documentElement.dataset.colorScheme = store.s.darkMode ? 'dark' : 'light';
|
window.document.documentElement.dataset.colorScheme = store.s.darkMode ? 'dark' : 'light';
|
||||||
|
|
||||||
const darkTheme = prefer.model('darkTheme');
|
const darkTheme = prefer.model('darkTheme');
|
||||||
const lightTheme = prefer.model('lightTheme');
|
const lightTheme = prefer.model('lightTheme');
|
||||||
@@ -201,20 +201,20 @@ export async function common(createVue: () => App<Element>) {
|
|||||||
}, { immediate: true });
|
}, { immediate: true });
|
||||||
|
|
||||||
watch(prefer.r.useBlurEffectForModal, v => {
|
watch(prefer.r.useBlurEffectForModal, v => {
|
||||||
document.documentElement.style.setProperty('--MI-modalBgFilter', v ? 'blur(4px)' : 'none');
|
window.document.documentElement.style.setProperty('--MI-modalBgFilter', v ? 'blur(4px)' : 'none');
|
||||||
}, { immediate: true });
|
}, { immediate: true });
|
||||||
|
|
||||||
watch(prefer.r.useBlurEffect, v => {
|
watch(prefer.r.useBlurEffect, v => {
|
||||||
if (v) {
|
if (v) {
|
||||||
document.documentElement.style.removeProperty('--MI-blur');
|
window.document.documentElement.style.removeProperty('--MI-blur');
|
||||||
} else {
|
} else {
|
||||||
document.documentElement.style.setProperty('--MI-blur', 'none');
|
window.document.documentElement.style.setProperty('--MI-blur', 'none');
|
||||||
}
|
}
|
||||||
}, { immediate: true });
|
}, { immediate: true });
|
||||||
|
|
||||||
// Keep screen on
|
// Keep screen on
|
||||||
const onVisibilityChange = () => document.addEventListener('visibilitychange', () => {
|
const onVisibilityChange = () => window.document.addEventListener('visibilitychange', () => {
|
||||||
if (document.visibilityState === 'visible') {
|
if (window.document.visibilityState === 'visible') {
|
||||||
navigator.wakeLock.request('screen');
|
navigator.wakeLock.request('screen');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -224,7 +224,7 @@ export async function common(createVue: () => App<Element>) {
|
|||||||
.catch(() => {
|
.catch(() => {
|
||||||
// On WebKit-based browsers, user activation is required to send wake lock request
|
// On WebKit-based browsers, user activation is required to send wake lock request
|
||||||
// https://webkit.org/blog/13862/the-user-activation-api/
|
// https://webkit.org/blog/13862/the-user-activation-api/
|
||||||
document.addEventListener(
|
window.document.addEventListener(
|
||||||
'click',
|
'click',
|
||||||
() => navigator.wakeLock.request('screen').then(onVisibilityChange),
|
() => navigator.wakeLock.request('screen').then(onVisibilityChange),
|
||||||
{ once: true },
|
{ once: true },
|
||||||
@@ -233,7 +233,7 @@ export async function common(createVue: () => App<Element>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (prefer.s.makeEveryTextElementsSelectable) {
|
if (prefer.s.makeEveryTextElementsSelectable) {
|
||||||
document.documentElement.classList.add('forceSelectableAll');
|
window.document.documentElement.classList.add('forceSelectableAll');
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region Fetch user
|
//#region Fetch user
|
||||||
@@ -278,16 +278,16 @@ export async function common(createVue: () => App<Element>) {
|
|||||||
const rootEl = ((): HTMLElement => {
|
const rootEl = ((): HTMLElement => {
|
||||||
const MISSKEY_MOUNT_DIV_ID = 'misskey_app';
|
const MISSKEY_MOUNT_DIV_ID = 'misskey_app';
|
||||||
|
|
||||||
const currentRoot = document.getElementById(MISSKEY_MOUNT_DIV_ID);
|
const currentRoot = window.document.getElementById(MISSKEY_MOUNT_DIV_ID);
|
||||||
|
|
||||||
if (currentRoot) {
|
if (currentRoot) {
|
||||||
console.warn('multiple import detected');
|
console.warn('multiple import detected');
|
||||||
return currentRoot;
|
return currentRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
const root = document.createElement('div');
|
const root = window.document.createElement('div');
|
||||||
root.id = MISSKEY_MOUNT_DIV_ID;
|
root.id = MISSKEY_MOUNT_DIV_ID;
|
||||||
document.body.appendChild(root);
|
window.document.body.appendChild(root);
|
||||||
return root;
|
return root;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
@@ -330,7 +330,7 @@ export async function common(createVue: () => App<Element>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function removeSplash() {
|
function removeSplash() {
|
||||||
const splash = document.getElementById('splash');
|
const splash = window.document.getElementById('splash');
|
||||||
if (splash) {
|
if (splash) {
|
||||||
splash.style.opacity = '0';
|
splash.style.opacity = '0';
|
||||||
splash.style.pointerEvents = 'none';
|
splash.style.pointerEvents = 'none';
|
||||||
|
@@ -43,7 +43,7 @@ export async function mainBoot() {
|
|||||||
if (!$i) uiStyle = 'visitor';
|
if (!$i) uiStyle = 'visitor';
|
||||||
|
|
||||||
if (searchParams.has('zen')) uiStyle = 'zen';
|
if (searchParams.has('zen')) uiStyle = 'zen';
|
||||||
if (uiStyle === 'deck' && prefer.s['deck.useSimpleUiForNonRootPages'] && location.pathname !== '/') uiStyle = 'zen';
|
if (uiStyle === 'deck' && prefer.s['deck.useSimpleUiForNonRootPages'] && window.location.pathname !== '/') uiStyle = 'zen';
|
||||||
|
|
||||||
if (searchParams.has('ui')) uiStyle = searchParams.get('ui');
|
if (searchParams.has('ui')) uiStyle = searchParams.get('ui');
|
||||||
|
|
||||||
@@ -216,7 +216,7 @@ export async function mainBoot() {
|
|||||||
let reloadDialogShowing = false;
|
let reloadDialogShowing = false;
|
||||||
stream.on('_disconnected_', async () => {
|
stream.on('_disconnected_', async () => {
|
||||||
if (prefer.s.serverDisconnectedBehavior === 'reload') {
|
if (prefer.s.serverDisconnectedBehavior === 'reload') {
|
||||||
location.reload();
|
window.location.reload();
|
||||||
} else if (prefer.s.serverDisconnectedBehavior === 'dialog') {
|
} else if (prefer.s.serverDisconnectedBehavior === 'dialog') {
|
||||||
if (reloadDialogShowing) return;
|
if (reloadDialogShowing) return;
|
||||||
reloadDialogShowing = true;
|
reloadDialogShowing = true;
|
||||||
@@ -227,7 +227,7 @@ export async function mainBoot() {
|
|||||||
});
|
});
|
||||||
reloadDialogShowing = false;
|
reloadDialogShowing = false;
|
||||||
if (!canceled) {
|
if (!canceled) {
|
||||||
location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -398,7 +398,7 @@ export async function mainBoot() {
|
|||||||
let lastVisibilityChangedAt = Date.now();
|
let lastVisibilityChangedAt = Date.now();
|
||||||
|
|
||||||
function claimPlainLucky() {
|
function claimPlainLucky() {
|
||||||
if (document.visibilityState !== 'visible') {
|
if (window.document.visibilityState !== 'visible') {
|
||||||
if (justPlainLuckyTimer != null) window.clearTimeout(justPlainLuckyTimer);
|
if (justPlainLuckyTimer != null) window.clearTimeout(justPlainLuckyTimer);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -413,7 +413,7 @@ export async function mainBoot() {
|
|||||||
window.addEventListener('visibilitychange', () => {
|
window.addEventListener('visibilitychange', () => {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
|
|
||||||
if (document.visibilityState === 'visible') {
|
if (window.document.visibilityState === 'visible') {
|
||||||
// タブを高速で切り替えたら取得処理が何度も走るのを防ぐ
|
// タブを高速で切り替えたら取得処理が何度も走るのを防ぐ
|
||||||
if ((now - lastVisibilityChangedAt) < 1000 * 10) {
|
if ((now - lastVisibilityChangedAt) < 1000 * 10) {
|
||||||
justPlainLuckyTimer = window.setTimeout(claimPlainLucky, 1000 * 10);
|
justPlainLuckyTimer = window.setTimeout(claimPlainLucky, 1000 * 10);
|
||||||
@@ -458,7 +458,7 @@ export async function mainBoot() {
|
|||||||
|
|
||||||
const latestDonationInfoShownAt = miLocalStorage.getItem('latestDonationInfoShownAt');
|
const latestDonationInfoShownAt = miLocalStorage.getItem('latestDonationInfoShownAt');
|
||||||
const neverShowDonationInfo = miLocalStorage.getItem('neverShowDonationInfo');
|
const neverShowDonationInfo = miLocalStorage.getItem('neverShowDonationInfo');
|
||||||
if (neverShowDonationInfo !== 'true' && (createdAt.getTime() < (Date.now() - (1000 * 60 * 60 * 24 * 3))) && !location.pathname.startsWith('/miauth')) {
|
if (neverShowDonationInfo !== 'true' && (createdAt.getTime() < (Date.now() - (1000 * 60 * 60 * 24 * 3))) && !window.location.pathname.startsWith('/miauth')) {
|
||||||
if (latestDonationInfoShownAt == null || (new Date(latestDonationInfoShownAt).getTime() < (Date.now() - (1000 * 60 * 60 * 24 * 30)))) {
|
if (latestDonationInfoShownAt == null || (new Date(latestDonationInfoShownAt).getTime() < (Date.now() - (1000 * 60 * 60 * 24 * 30)))) {
|
||||||
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkDonation.vue')), {}, {
|
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkDonation.vue')), {}, {
|
||||||
closed: () => dispose(),
|
closed: () => dispose(),
|
||||||
@@ -554,7 +554,7 @@ export async function mainBoot() {
|
|||||||
mainRouter.push('/search');
|
mainRouter.push('/search');
|
||||||
},
|
},
|
||||||
} as const satisfies Keymap;
|
} as const satisfies Keymap;
|
||||||
document.addEventListener('keydown', makeHotkey(keymap), { passive: false });
|
window.document.addEventListener('keydown', makeHotkey(keymap), { passive: false });
|
||||||
|
|
||||||
initializeSw();
|
initializeSw();
|
||||||
}
|
}
|
||||||
|
@@ -192,7 +192,7 @@ function tick() {
|
|||||||
tick();
|
tick();
|
||||||
|
|
||||||
function calcColors() {
|
function calcColors() {
|
||||||
const computedStyle = getComputedStyle(document.documentElement);
|
const computedStyle = getComputedStyle(window.document.documentElement);
|
||||||
const dark = tinycolor(computedStyle.getPropertyValue('--MI_THEME-bg')).isDark();
|
const dark = tinycolor(computedStyle.getPropertyValue('--MI_THEME-bg')).isDark();
|
||||||
const accent = tinycolor(computedStyle.getPropertyValue('--MI_THEME-accent')).toHexString();
|
const accent = tinycolor(computedStyle.getPropertyValue('--MI_THEME-accent')).toHexString();
|
||||||
majorGraduationColor.value = dark ? 'rgba(255, 255, 255, 0.3)' : 'rgba(0, 0, 0, 0.3)';
|
majorGraduationColor.value = dark ? 'rgba(255, 255, 255, 0.3)' : 'rgba(0, 0, 0, 0.3)';
|
||||||
|
@@ -359,7 +359,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
props.textarea.addEventListener('keydown', onKeydown);
|
props.textarea.addEventListener('keydown', onKeydown);
|
||||||
|
|
||||||
document.body.addEventListener('mousedown', onMousedown);
|
window.document.body.addEventListener('mousedown', onMousedown);
|
||||||
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
exec();
|
exec();
|
||||||
@@ -375,7 +375,7 @@ onMounted(() => {
|
|||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
props.textarea.removeEventListener('keydown', onKeydown);
|
props.textarea.removeEventListener('keydown', onKeydown);
|
||||||
|
|
||||||
document.body.removeEventListener('mousedown', onMousedown);
|
window.document.body.removeEventListener('mousedown', onMousedown);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@@ -92,7 +92,7 @@ function onMousedown(evt: MouseEvent): void {
|
|||||||
const target = evt.target! as HTMLElement;
|
const target = evt.target! as HTMLElement;
|
||||||
const rect = target.getBoundingClientRect();
|
const rect = target.getBoundingClientRect();
|
||||||
|
|
||||||
const ripple = document.createElement('div');
|
const ripple = window.document.createElement('div');
|
||||||
ripple.classList.add(ripples.value!.dataset.childrenClass!);
|
ripple.classList.add(ripples.value!.dataset.childrenClass!);
|
||||||
ripple.style.top = (evt.clientY - rect.top - 1).toString() + 'px';
|
ripple.style.top = (evt.clientY - rect.top - 1).toString() + 'px';
|
||||||
ripple.style.left = (evt.clientX - rect.left - 1).toString() + 'px';
|
ripple.style.left = (evt.clientX - rect.left - 1).toString() + 'px';
|
||||||
|
@@ -112,7 +112,7 @@ watch(() => [props.instanceUrl, props.sitekey, props.secretKey], async () => {
|
|||||||
if (loaded || props.provider === 'mcaptcha' || props.provider === 'testcaptcha') {
|
if (loaded || props.provider === 'mcaptcha' || props.provider === 'testcaptcha') {
|
||||||
available.value = true;
|
available.value = true;
|
||||||
} else if (src.value !== null) {
|
} else if (src.value !== null) {
|
||||||
(document.getElementById(scriptId.value) ?? document.head.appendChild(Object.assign(document.createElement('script'), {
|
(window.document.getElementById(scriptId.value) ?? window.document.head.appendChild(Object.assign(window.document.createElement('script'), {
|
||||||
async: true,
|
async: true,
|
||||||
id: scriptId.value,
|
id: scriptId.value,
|
||||||
src: src.value,
|
src: src.value,
|
||||||
@@ -149,7 +149,7 @@ async function requestRender() {
|
|||||||
if (captcha.value.render && captchaEl.value instanceof Element && props.sitekey) {
|
if (captcha.value.render && captchaEl.value instanceof Element && props.sitekey) {
|
||||||
// reCAPTCHAのレンダリング重複判定を回避するため、captchaEl配下に仮のdivを用意する.
|
// reCAPTCHAのレンダリング重複判定を回避するため、captchaEl配下に仮のdivを用意する.
|
||||||
// (同じdivに対して複数回renderを呼び出すとreCAPTCHAはエラーを返すので)
|
// (同じdivに対して複数回renderを呼び出すとreCAPTCHAはエラーを返すので)
|
||||||
const elem = document.createElement('div');
|
const elem = window.document.createElement('div');
|
||||||
captchaEl.value.appendChild(elem);
|
captchaEl.value.appendChild(elem);
|
||||||
|
|
||||||
captchaWidgetId.value = captcha.value.render(elem, {
|
captchaWidgetId.value = captcha.value.render(elem, {
|
||||||
@@ -174,7 +174,7 @@ async function requestRender() {
|
|||||||
|
|
||||||
function clearWidget() {
|
function clearWidget() {
|
||||||
if (props.provider === 'mcaptcha') {
|
if (props.provider === 'mcaptcha') {
|
||||||
const container = document.getElementById('mcaptcha__widget-container');
|
const container = window.document.getElementById('mcaptcha__widget-container');
|
||||||
if (container) {
|
if (container) {
|
||||||
container.innerHTML = '';
|
container.innerHTML = '';
|
||||||
}
|
}
|
||||||
|
@@ -68,11 +68,11 @@ onMounted(() => {
|
|||||||
rootEl.value.style.left = `${left}px`;
|
rootEl.value.style.left = `${left}px`;
|
||||||
}
|
}
|
||||||
|
|
||||||
document.body.addEventListener('mousedown', onMousedown);
|
window.document.body.addEventListener('mousedown', onMousedown);
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
document.body.removeEventListener('mousedown', onMousedown);
|
window.document.body.removeEventListener('mousedown', onMousedown);
|
||||||
});
|
});
|
||||||
|
|
||||||
function onMousedown(evt: Event) {
|
function onMousedown(evt: Event) {
|
||||||
|
@@ -3,14 +3,12 @@
|
|||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
/* eslint-disable import/no-default-export */
|
|
||||||
import type { StoryObj } from '@storybook/vue3';
|
|
||||||
import { HttpResponse, http } from 'msw';
|
import { HttpResponse, http } from 'msw';
|
||||||
import { action } from '@storybook/addon-actions';
|
import { action } from '@storybook/addon-actions';
|
||||||
import { file } from '../../.storybook/fakes.js';
|
import { file } from '../../.storybook/fakes.js';
|
||||||
import { commonHandlers } from '../../.storybook/mocks.js';
|
import { commonHandlers } from '../../.storybook/mocks.js';
|
||||||
import MkCropperDialog from './MkCropperDialog.vue';
|
import MkCropperDialog from './MkCropperDialog.vue';
|
||||||
|
import type { StoryObj } from '@storybook/vue3';
|
||||||
export const Default = {
|
export const Default = {
|
||||||
render(args) {
|
render(args) {
|
||||||
return {
|
return {
|
||||||
@@ -55,7 +53,7 @@ export const Default = {
|
|||||||
http.get('/proxy/image.webp', async ({ request }) => {
|
http.get('/proxy/image.webp', async ({ request }) => {
|
||||||
const url = new URL(request.url).searchParams.get('url');
|
const url = new URL(request.url).searchParams.get('url');
|
||||||
if (url === 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true') {
|
if (url === 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true') {
|
||||||
const image = await (await fetch('client-assets/fedi.jpg')).blob();
|
const image = await (await window.fetch('client-assets/fedi.jpg')).blob();
|
||||||
return new HttpResponse(image, {
|
return new HttpResponse(image, {
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'image/jpeg',
|
'Content-Type': 'image/jpeg',
|
||||||
|
@@ -122,7 +122,7 @@ onMounted(() => {
|
|||||||
cropper = new Cropper(imgEl.value!, {
|
cropper = new Cropper(imgEl.value!, {
|
||||||
});
|
});
|
||||||
|
|
||||||
const computedStyle = getComputedStyle(document.documentElement);
|
const computedStyle = getComputedStyle(window.document.documentElement);
|
||||||
|
|
||||||
const selection = cropper.getCropperSelection()!;
|
const selection = cropper.getCropperSelection()!;
|
||||||
selection.themeColor = tinycolor(computedStyle.getPropertyValue('--MI_THEME-accent')).toHexString();
|
selection.themeColor = tinycolor(computedStyle.getPropertyValue('--MI_THEME-accent')).toHexString();
|
||||||
|
@@ -180,7 +180,7 @@ function applyToPreview() {
|
|||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
if (currentPreviewUrl === embedPreviewUrl.value) {
|
if (currentPreviewUrl === embedPreviewUrl.value) {
|
||||||
// URLが変わらなくてもリロード
|
// URLが変わらなくてもリロード
|
||||||
iframeEl.value?.contentWindow?.location.reload();
|
iframeEl.value?.contentWindow?.window.location.reload();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -116,7 +116,7 @@ function toggle() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const computedStyle = getComputedStyle(document.documentElement);
|
const computedStyle = getComputedStyle(window.document.documentElement);
|
||||||
const parentBg = getBgColor(rootEl.value?.parentElement) ?? 'transparent';
|
const parentBg = getBgColor(rootEl.value?.parentElement) ?? 'transparent';
|
||||||
const myBg = computedStyle.getPropertyValue('--MI_THEME-panel');
|
const myBg = computedStyle.getPropertyValue('--MI_THEME-panel');
|
||||||
bgSame.value = parentBg === myBg;
|
bgSame.value = parentBg === myBg;
|
||||||
|
@@ -19,9 +19,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
:leaveToClass="transitionName === 'swipeAnimationLeft' ? $style.swipeAnimationLeft_leaveTo : $style.swipeAnimationRight_leaveTo"
|
:leaveToClass="transitionName === 'swipeAnimationLeft' ? $style.swipeAnimationLeft_leaveTo : $style.swipeAnimationRight_leaveTo"
|
||||||
:style="`--swipe: ${pullDistance}px;`"
|
:style="`--swipe: ${pullDistance}px;`"
|
||||||
>
|
>
|
||||||
<!-- 【注意】slot内の最上位要素に動的にkeyを設定すること -->
|
<div :key="tabModel">
|
||||||
<!-- 各最上位要素にユニークなkeyの指定がないとTransitionがうまく動きません -->
|
<slot></slot>
|
||||||
<slot></slot>
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@@ -55,7 +55,7 @@ import { extractAvgColorFromBlurhash } from '@@/js/extract-avg-color-from-blurha
|
|||||||
const canvasPromise = new Promise<WorkerMultiDispatch | HTMLCanvasElement>(resolve => {
|
const canvasPromise = new Promise<WorkerMultiDispatch | HTMLCanvasElement>(resolve => {
|
||||||
// テスト環境で Web Worker インスタンスは作成できない
|
// テスト環境で Web Worker インスタンスは作成できない
|
||||||
if (import.meta.env.MODE === 'test') {
|
if (import.meta.env.MODE === 'test') {
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = window.document.createElement('canvas');
|
||||||
canvas.width = 64;
|
canvas.width = 64;
|
||||||
canvas.height = 64;
|
canvas.height = 64;
|
||||||
resolve(canvas);
|
resolve(canvas);
|
||||||
@@ -70,7 +70,7 @@ const canvasPromise = new Promise<WorkerMultiDispatch | HTMLCanvasElement>(resol
|
|||||||
);
|
);
|
||||||
resolve(workers);
|
resolve(workers);
|
||||||
} else {
|
} else {
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = window.document.createElement('canvas');
|
||||||
canvas.width = 64;
|
canvas.width = 64;
|
||||||
canvas.height = 64;
|
canvas.height = 64;
|
||||||
resolve(canvas);
|
resolve(canvas);
|
||||||
|
@@ -3,13 +3,12 @@
|
|||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
||||||
import type { StoryObj } from '@storybook/vue3';
|
|
||||||
import { HttpResponse, http } from 'msw';
|
import { HttpResponse, http } from 'msw';
|
||||||
import { federationInstance } from '../../.storybook/fakes.js';
|
import { federationInstance } from '../../.storybook/fakes.js';
|
||||||
import { commonHandlers } from '../../.storybook/mocks.js';
|
import { commonHandlers } from '../../.storybook/mocks.js';
|
||||||
import { getChartResolver } from '../../.storybook/charts.js';
|
import { getChartResolver } from '../../.storybook/charts.js';
|
||||||
import MkInstanceCardMini from './MkInstanceCardMini.vue';
|
import MkInstanceCardMini from './MkInstanceCardMini.vue';
|
||||||
|
import type { StoryObj } from '@storybook/vue3';
|
||||||
|
|
||||||
export const Default = {
|
export const Default = {
|
||||||
render(args) {
|
render(args) {
|
||||||
@@ -48,7 +47,7 @@ export const Default = {
|
|||||||
const url = new URL(urlStr);
|
const url = new URL(urlStr);
|
||||||
|
|
||||||
if (url.href.startsWith('https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/')) {
|
if (url.href.startsWith('https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/')) {
|
||||||
const image = await (await fetch(`client-assets/${url.pathname.split('/').pop()}`)).blob();
|
const image = await (await window.fetch(`client-assets/${url.pathname.split('/').pop()}`)).blob();
|
||||||
return new HttpResponse(image, {
|
return new HttpResponse(image, {
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'image/jpeg',
|
'Content-Type': 'image/jpeg',
|
||||||
|
@@ -126,7 +126,7 @@ function createDoughnut(chartEl, tooltip, data) {
|
|||||||
labels: data.map(x => x.name),
|
labels: data.map(x => x.name),
|
||||||
datasets: [{
|
datasets: [{
|
||||||
backgroundColor: data.map(x => x.color),
|
backgroundColor: data.map(x => x.color),
|
||||||
borderColor: getComputedStyle(document.documentElement).getPropertyValue('--MI_THEME-panel'),
|
borderColor: getComputedStyle(window.document.documentElement).getPropertyValue('--MI_THEME-panel'),
|
||||||
borderWidth: 2,
|
borderWidth: 2,
|
||||||
hoverOffset: 0,
|
hoverOffset: 0,
|
||||||
data: data.map(x => x.value),
|
data: data.map(x => x.value),
|
||||||
|
@@ -148,7 +148,7 @@ const keymap = {
|
|||||||
// PlayerElもしくはその子要素にフォーカスがあるかどうか
|
// PlayerElもしくはその子要素にフォーカスがあるかどうか
|
||||||
function hasFocus() {
|
function hasFocus() {
|
||||||
if (!playerEl.value) return false;
|
if (!playerEl.value) return false;
|
||||||
return playerEl.value === document.activeElement || playerEl.value.contains(document.activeElement);
|
return playerEl.value === window.document.activeElement || playerEl.value.contains(window.document.activeElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
const playerEl = useTemplateRef('playerEl');
|
const playerEl = useTemplateRef('playerEl');
|
||||||
|
@@ -48,7 +48,7 @@ const props = defineProps<{
|
|||||||
|
|
||||||
const gallery = useTemplateRef('gallery');
|
const gallery = useTemplateRef('gallery');
|
||||||
const pswpZIndex = os.claimZIndex('middle');
|
const pswpZIndex = os.claimZIndex('middle');
|
||||||
document.documentElement.style.setProperty('--mk-pswp-root-z-index', pswpZIndex.toString());
|
window.document.documentElement.style.setProperty('--mk-pswp-root-z-index', pswpZIndex.toString());
|
||||||
const count = computed(() => props.mediaList.filter(media => previewable(media)).length);
|
const count = computed(() => props.mediaList.filter(media => previewable(media)).length);
|
||||||
let lightbox: PhotoSwipeLightbox | null = null;
|
let lightbox: PhotoSwipeLightbox | null = null;
|
||||||
|
|
||||||
@@ -166,7 +166,7 @@ onMounted(() => {
|
|||||||
className: 'pswp__alt-text-container',
|
className: 'pswp__alt-text-container',
|
||||||
appendTo: 'wrapper',
|
appendTo: 'wrapper',
|
||||||
onInit: (el, pswp) => {
|
onInit: (el, pswp) => {
|
||||||
const textBox = document.createElement('p');
|
const textBox = window.document.createElement('p');
|
||||||
textBox.className = 'pswp__alt-text _acrylic';
|
textBox.className = 'pswp__alt-text _acrylic';
|
||||||
el.appendChild(textBox);
|
el.appendChild(textBox);
|
||||||
|
|
||||||
@@ -178,19 +178,19 @@ onMounted(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
lightbox.on('afterInit', () => {
|
lightbox.on('afterInit', () => {
|
||||||
activeEl = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
activeEl = window.document.activeElement instanceof HTMLElement ? window.document.activeElement : null;
|
||||||
focusParent(activeEl, true, true);
|
focusParent(activeEl, true, true);
|
||||||
lightbox?.pswp?.element?.focus({
|
lightbox?.pswp?.element?.focus({
|
||||||
preventScroll: true,
|
preventScroll: true,
|
||||||
});
|
});
|
||||||
history.pushState(null, '', '#pswp');
|
window.history.pushState(null, '', '#pswp');
|
||||||
});
|
});
|
||||||
|
|
||||||
lightbox.on('destroy', () => {
|
lightbox.on('destroy', () => {
|
||||||
focusParent(activeEl, true, false);
|
focusParent(activeEl, true, false);
|
||||||
activeEl = null;
|
activeEl = null;
|
||||||
if (window.location.hash === '#pswp') {
|
if (window.location.hash === '#pswp') {
|
||||||
history.back();
|
window.history.back();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -171,7 +171,7 @@ const keymap = {
|
|||||||
// PlayerElもしくはその子要素にフォーカスがあるかどうか
|
// PlayerElもしくはその子要素にフォーカスがあるかどうか
|
||||||
function hasFocus() {
|
function hasFocus() {
|
||||||
if (!playerEl.value) return false;
|
if (!playerEl.value) return false;
|
||||||
return playerEl.value === document.activeElement || playerEl.value.contains(document.activeElement);
|
return playerEl.value === window.document.activeElement || playerEl.value.contains(window.document.activeElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
|
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
|
||||||
@@ -216,7 +216,7 @@ function showMenu(ev: MouseEvent) {
|
|||||||
'2.0x': 2,
|
'2.0x': 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
...(document.pictureInPictureEnabled ? [{
|
...(window.document.pictureInPictureEnabled ? [{
|
||||||
text: i18n.ts._mediaControls.pip,
|
text: i18n.ts._mediaControls.pip,
|
||||||
icon: 'ti ti-picture-in-picture',
|
icon: 'ti ti-picture-in-picture',
|
||||||
action: togglePictureInPicture,
|
action: togglePictureInPicture,
|
||||||
@@ -384,8 +384,8 @@ function toggleFullscreen() {
|
|||||||
|
|
||||||
function togglePictureInPicture() {
|
function togglePictureInPicture() {
|
||||||
if (videoEl.value) {
|
if (videoEl.value) {
|
||||||
if (document.pictureInPictureElement) {
|
if (window.document.pictureInPictureElement) {
|
||||||
document.exitPictureInPicture();
|
window.document.exitPictureInPicture();
|
||||||
} else {
|
} else {
|
||||||
videoEl.value.requestPictureInPicture();
|
videoEl.value.requestPictureInPicture();
|
||||||
}
|
}
|
||||||
|
@@ -358,10 +358,10 @@ function switchItem(item: MenuSwitch & { ref: any }) {
|
|||||||
|
|
||||||
function focusUp() {
|
function focusUp() {
|
||||||
if (disposed) return;
|
if (disposed) return;
|
||||||
if (!itemsEl.value?.contains(document.activeElement)) return;
|
if (!itemsEl.value?.contains(window.document.activeElement)) return;
|
||||||
|
|
||||||
const focusableElements = Array.from(itemsEl.value.children).filter(isFocusable);
|
const focusableElements = Array.from(itemsEl.value.children).filter(isFocusable);
|
||||||
const activeIndex = focusableElements.findIndex(el => el === document.activeElement);
|
const activeIndex = focusableElements.findIndex(el => el === window.document.activeElement);
|
||||||
const targetIndex = (activeIndex !== -1 && activeIndex !== 0) ? (activeIndex - 1) : (focusableElements.length - 1);
|
const targetIndex = (activeIndex !== -1 && activeIndex !== 0) ? (activeIndex - 1) : (focusableElements.length - 1);
|
||||||
const targetElement = focusableElements.at(targetIndex) ?? itemsEl.value;
|
const targetElement = focusableElements.at(targetIndex) ?? itemsEl.value;
|
||||||
|
|
||||||
@@ -370,10 +370,10 @@ function focusUp() {
|
|||||||
|
|
||||||
function focusDown() {
|
function focusDown() {
|
||||||
if (disposed) return;
|
if (disposed) return;
|
||||||
if (!itemsEl.value?.contains(document.activeElement)) return;
|
if (!itemsEl.value?.contains(window.document.activeElement)) return;
|
||||||
|
|
||||||
const focusableElements = Array.from(itemsEl.value.children).filter(isFocusable);
|
const focusableElements = Array.from(itemsEl.value.children).filter(isFocusable);
|
||||||
const activeIndex = focusableElements.findIndex(el => el === document.activeElement);
|
const activeIndex = focusableElements.findIndex(el => el === window.document.activeElement);
|
||||||
const targetIndex = (activeIndex !== -1 && activeIndex !== (focusableElements.length - 1)) ? (activeIndex + 1) : 0;
|
const targetIndex = (activeIndex !== -1 && activeIndex !== (focusableElements.length - 1)) ? (activeIndex + 1) : 0;
|
||||||
const targetElement = focusableElements.at(targetIndex) ?? itemsEl.value;
|
const targetElement = focusableElements.at(targetIndex) ?? itemsEl.value;
|
||||||
|
|
||||||
@@ -400,9 +400,9 @@ const onGlobalMousedown = (ev: MouseEvent) => {
|
|||||||
|
|
||||||
const setupHandlers = () => {
|
const setupHandlers = () => {
|
||||||
if (!isNestingMenu) {
|
if (!isNestingMenu) {
|
||||||
document.addEventListener('focusin', onGlobalFocusin, { passive: true });
|
window.document.addEventListener('focusin', onGlobalFocusin, { passive: true });
|
||||||
}
|
}
|
||||||
document.addEventListener('mousedown', onGlobalMousedown, { passive: true });
|
window.document.addEventListener('mousedown', onGlobalMousedown, { passive: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
let disposed = false;
|
let disposed = false;
|
||||||
@@ -410,9 +410,9 @@ let disposed = false;
|
|||||||
const disposeHandlers = () => {
|
const disposeHandlers = () => {
|
||||||
disposed = true;
|
disposed = true;
|
||||||
if (!isNestingMenu) {
|
if (!isNestingMenu) {
|
||||||
document.removeEventListener('focusin', onGlobalFocusin);
|
window.document.removeEventListener('focusin', onGlobalFocusin);
|
||||||
}
|
}
|
||||||
document.removeEventListener('mousedown', onGlobalMousedown);
|
window.document.removeEventListener('mousedown', onGlobalMousedown);
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@@ -48,7 +48,7 @@ const polygonPoints = ref('');
|
|||||||
const headX = ref<number | null>(null);
|
const headX = ref<number | null>(null);
|
||||||
const headY = ref<number | null>(null);
|
const headY = ref<number | null>(null);
|
||||||
const clock = ref<number | null>(null);
|
const clock = ref<number | null>(null);
|
||||||
const accent = tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--MI_THEME-accent'));
|
const accent = tinycolor(getComputedStyle(window.document.documentElement).getPropertyValue('--MI_THEME-accent'));
|
||||||
const color = accent.toRgbString();
|
const color = accent.toRgbString();
|
||||||
|
|
||||||
function draw(): void {
|
function draw(): void {
|
||||||
|
@@ -59,7 +59,7 @@ const pagination = computed(() => prefer.r.useGroupedNotifications.value ? {
|
|||||||
|
|
||||||
function onNotification(notification) {
|
function onNotification(notification) {
|
||||||
const isMuted = props.excludeTypes ? props.excludeTypes.includes(notification.type) : false;
|
const isMuted = props.excludeTypes ? props.excludeTypes.includes(notification.type) : false;
|
||||||
if (isMuted || document.visibilityState === 'visible') {
|
if (isMuted || window.document.visibilityState === 'visible') {
|
||||||
useStream().send('readNotification');
|
useStream().send('readNotification');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -142,7 +142,7 @@ const {
|
|||||||
} = prefer.r;
|
} = prefer.r;
|
||||||
|
|
||||||
const contentEl = computed(() => props.pagination.pageEl ?? rootEl.value);
|
const contentEl = computed(() => props.pagination.pageEl ?? rootEl.value);
|
||||||
const scrollableElement = computed(() => contentEl.value ? getScrollContainer(contentEl.value) : document.body);
|
const scrollableElement = computed(() => contentEl.value ? getScrollContainer(contentEl.value) : window.document.body);
|
||||||
|
|
||||||
const visibility = useDocumentVisibility();
|
const visibility = useDocumentVisibility();
|
||||||
|
|
||||||
|
@@ -151,9 +151,9 @@ function onMousedown(ev: MouseEvent | TouchEvent) {
|
|||||||
closed: () => dispose(),
|
closed: () => dispose(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const style = document.createElement('style');
|
const style = window.document.createElement('style');
|
||||||
style.appendChild(document.createTextNode('* { cursor: grabbing !important; } body * { pointer-events: none !important; }'));
|
style.appendChild(window.document.createTextNode('* { cursor: grabbing !important; } body * { pointer-events: none !important; }'));
|
||||||
document.head.appendChild(style);
|
window.document.head.appendChild(style);
|
||||||
|
|
||||||
const thumbWidth = getThumbWidth();
|
const thumbWidth = getThumbWidth();
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ function onMousedown(ev: MouseEvent | TouchEvent) {
|
|||||||
let beforeValue = finalValue.value;
|
let beforeValue = finalValue.value;
|
||||||
|
|
||||||
const onMouseup = () => {
|
const onMouseup = () => {
|
||||||
document.head.removeChild(style);
|
window.document.head.removeChild(style);
|
||||||
tooltipForDragShowing.value = false;
|
tooltipForDragShowing.value = false;
|
||||||
window.removeEventListener('mousemove', onDrag);
|
window.removeEventListener('mousemove', onDrag);
|
||||||
window.removeEventListener('touchmove', onDrag);
|
window.removeEventListener('touchmove', onDrag);
|
||||||
|
@@ -136,7 +136,7 @@ async function menu(ev) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function anime() {
|
function anime() {
|
||||||
if (document.hidden || !prefer.s.animation || buttonEl.value == null) return;
|
if (window.document.hidden || !prefer.s.animation || buttonEl.value == null) return;
|
||||||
|
|
||||||
const rect = buttonEl.value.getBoundingClientRect();
|
const rect = buttonEl.value.getBoundingClientRect();
|
||||||
const x = rect.left + 16;
|
const x = rect.left + 16;
|
||||||
|
@@ -44,7 +44,7 @@ onMounted(async () => {
|
|||||||
|
|
||||||
const vLineColor = store.s.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
const vLineColor = store.s.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
||||||
|
|
||||||
const accent = tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--MI_THEME-accent'));
|
const accent = tinycolor(getComputedStyle(window.document.documentElement).getPropertyValue('--MI_THEME-accent'));
|
||||||
const color = accent.toHex();
|
const color = accent.toHex();
|
||||||
|
|
||||||
if (chartEl.value == null) return;
|
if (chartEl.value == null) return;
|
||||||
|
@@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
:width="400"
|
:width="400"
|
||||||
:height="500"
|
:height="500"
|
||||||
@close="onCloseModalWindow"
|
@close="onCloseModalWindow"
|
||||||
@closed="console.log('MkRoleSelectDialog: closed') ; $emit('dispose')"
|
@closed="emit('closed')"
|
||||||
>
|
>
|
||||||
<template #header>{{ title }}</template>
|
<template #header>{{ title }}</template>
|
||||||
<MkSpacer :marginMin="20" :marginMax="28">
|
<MkSpacer :marginMin="20" :marginMax="28">
|
||||||
@@ -58,7 +58,7 @@ import MkLoading from '@/components/global/MkLoading.vue';
|
|||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'done', value: Misskey.entities.Role[]),
|
(ev: 'done', value: Misskey.entities.Role[]),
|
||||||
(ev: 'close'),
|
(ev: 'close'),
|
||||||
(ev: 'dispose'),
|
(ev: 'closed'),
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
|
@@ -267,7 +267,7 @@ async function onSubmit(): Promise<void> {
|
|||||||
'testcaptcha-response': testcaptchaResponse.value,
|
'testcaptcha-response': testcaptchaResponse.value,
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await fetch(`${config.apiUrl}/signup`, {
|
const res = await window.fetch(`${config.apiUrl}/signup`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
@@ -20,7 +20,7 @@ import tinycolor from 'tinycolor2';
|
|||||||
|
|
||||||
const loaded = !!window.TagCanvas;
|
const loaded = !!window.TagCanvas;
|
||||||
const SAFE_FOR_HTML_ID = 'abcdefghijklmnopqrstuvwxyz';
|
const SAFE_FOR_HTML_ID = 'abcdefghijklmnopqrstuvwxyz';
|
||||||
const computedStyle = getComputedStyle(document.documentElement);
|
const computedStyle = getComputedStyle(window.document.documentElement);
|
||||||
const idForCanvas = Array.from({ length: 16 }, () => SAFE_FOR_HTML_ID[Math.floor(Math.random() * SAFE_FOR_HTML_ID.length)]).join('');
|
const idForCanvas = Array.from({ length: 16 }, () => SAFE_FOR_HTML_ID[Math.floor(Math.random() * SAFE_FOR_HTML_ID.length)]).join('');
|
||||||
const idForTags = Array.from({ length: 16 }, () => SAFE_FOR_HTML_ID[Math.floor(Math.random() * SAFE_FOR_HTML_ID.length)]).join('');
|
const idForTags = Array.from({ length: 16 }, () => SAFE_FOR_HTML_ID[Math.floor(Math.random() * SAFE_FOR_HTML_ID.length)]).join('');
|
||||||
const available = ref(false);
|
const available = ref(false);
|
||||||
@@ -57,7 +57,7 @@ onMounted(() => {
|
|||||||
if (loaded) {
|
if (loaded) {
|
||||||
available.value = true;
|
available.value = true;
|
||||||
} else {
|
} else {
|
||||||
document.head.appendChild(Object.assign(document.createElement('script'), {
|
window.document.head.appendChild(Object.assign(window.document.createElement('script'), {
|
||||||
async: true,
|
async: true,
|
||||||
src: '/client-assets/tagcanvas.min.js',
|
src: '/client-assets/tagcanvas.min.js',
|
||||||
})).addEventListener('load', () => available.value = true);
|
})).addEventListener('load', () => available.value = true);
|
||||||
|
@@ -61,7 +61,7 @@ async function renderChart() {
|
|||||||
|
|
||||||
const vLineColor = store.s.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
const vLineColor = store.s.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
||||||
|
|
||||||
const computedStyle = getComputedStyle(document.documentElement);
|
const computedStyle = getComputedStyle(window.document.documentElement);
|
||||||
const accent = tinycolor(computedStyle.getPropertyValue('--MI_THEME-accent')).toHexString();
|
const accent = tinycolor(computedStyle.getPropertyValue('--MI_THEME-accent')).toHexString();
|
||||||
|
|
||||||
const colorRead = accent;
|
const colorRead = accent;
|
||||||
|
@@ -240,7 +240,7 @@ function onHeaderMousedown(evt: MouseEvent | TouchEvent) {
|
|||||||
const main = rootEl.value;
|
const main = rootEl.value;
|
||||||
if (main == null) return;
|
if (main == null) return;
|
||||||
|
|
||||||
if (!contains(main, document.activeElement)) main.focus();
|
if (!contains(main, window.document.activeElement)) main.focus();
|
||||||
|
|
||||||
const position = main.getBoundingClientRect();
|
const position = main.getBoundingClientRect();
|
||||||
|
|
||||||
|
@@ -87,7 +87,7 @@ function openWindow() {
|
|||||||
|
|
||||||
function nav(ev: MouseEvent) {
|
function nav(ev: MouseEvent) {
|
||||||
if (behavior === 'browser') {
|
if (behavior === 'browser') {
|
||||||
location.href = props.to;
|
window.location.href = props.to;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -170,7 +170,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
if (props.rootEl) {
|
if (props.rootEl) {
|
||||||
ro2 = new ResizeObserver((entries, observer) => {
|
ro2 = new ResizeObserver((entries, observer) => {
|
||||||
if (document.body.contains(el.value as HTMLElement)) {
|
if (window.document.body.contains(el.value as HTMLElement)) {
|
||||||
nextTick(() => renderTab());
|
nextTick(() => renderTab());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@@ -69,6 +69,8 @@ const emit = defineEmits<{
|
|||||||
(ev: 'update:tab', key: string);
|
(ev: 'update:tab', key: string);
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const viewId = inject(DI.viewId);
|
||||||
|
const viewTransitionName = computed(() => `${viewId}---pageHeader`);
|
||||||
const injectedPageMetadata = inject(DI.pageMetadata);
|
const injectedPageMetadata = inject(DI.pageMetadata);
|
||||||
const pageMetadata = computed(() => props.overridePageMetadata ?? injectedPageMetadata.value);
|
const pageMetadata = computed(() => props.overridePageMetadata ?? injectedPageMetadata.value);
|
||||||
|
|
||||||
@@ -106,7 +108,7 @@ function onTabClick(): void {
|
|||||||
|
|
||||||
const calcBg = () => {
|
const calcBg = () => {
|
||||||
const rawBg = 'var(--MI_THEME-bg)';
|
const rawBg = 'var(--MI_THEME-bg)';
|
||||||
const tinyBg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg);
|
const tinyBg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(window.document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg);
|
||||||
tinyBg.setAlpha(0.85);
|
tinyBg.setAlpha(0.85);
|
||||||
bg.value = tinyBg.toRgbString();
|
bg.value = tinyBg.toRgbString();
|
||||||
};
|
};
|
||||||
@@ -120,7 +122,7 @@ onMounted(() => {
|
|||||||
if (el.value && el.value.parentElement) {
|
if (el.value && el.value.parentElement) {
|
||||||
narrow.value = el.value.parentElement.offsetWidth < 500;
|
narrow.value = el.value.parentElement.offsetWidth < 500;
|
||||||
ro = new ResizeObserver((entries, observer) => {
|
ro = new ResizeObserver((entries, observer) => {
|
||||||
if (el.value && el.value.parentElement && document.body.contains(el.value as HTMLElement)) {
|
if (el.value && el.value.parentElement && window.document.body.contains(el.value as HTMLElement)) {
|
||||||
narrow.value = el.value.parentElement.offsetWidth < 500;
|
narrow.value = el.value.parentElement.offsetWidth < 500;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -140,6 +142,7 @@ onUnmounted(() => {
|
|||||||
backdrop-filter: var(--MI-blur, blur(15px));
|
backdrop-filter: var(--MI-blur, blur(15px));
|
||||||
border-bottom: solid 0.5px var(--MI_THEME-divider);
|
border-bottom: solid 0.5px var(--MI_THEME-divider);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
view-transition-name: v-bind(viewTransitionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
.upper,
|
.upper,
|
||||||
|
@@ -23,8 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onUnmounted, provide, inject, ref, watch, useTemplateRef } from 'vue';
|
import { onMounted, onUnmounted, provide, inject, ref, watch, useTemplateRef } from 'vue';
|
||||||
import { CURRENT_STICKY_BOTTOM, CURRENT_STICKY_TOP } from '@@/js/const.js';
|
import { DI } from '@/di.js';
|
||||||
import type { Ref } from 'vue';
|
|
||||||
|
|
||||||
const rootEl = useTemplateRef('rootEl');
|
const rootEl = useTemplateRef('rootEl');
|
||||||
const headerEl = useTemplateRef('headerEl');
|
const headerEl = useTemplateRef('headerEl');
|
||||||
@@ -32,13 +31,13 @@ const footerEl = useTemplateRef('footerEl');
|
|||||||
|
|
||||||
const headerHeight = ref<string | undefined>();
|
const headerHeight = ref<string | undefined>();
|
||||||
const childStickyTop = ref(0);
|
const childStickyTop = ref(0);
|
||||||
const parentStickyTop = inject<Ref<number>>(CURRENT_STICKY_TOP, ref(0));
|
const parentStickyTop = inject(DI.currentStickyTop, ref(0));
|
||||||
provide(CURRENT_STICKY_TOP, childStickyTop);
|
provide(DI.currentStickyTop, childStickyTop);
|
||||||
|
|
||||||
const footerHeight = ref<string | undefined>();
|
const footerHeight = ref<string | undefined>();
|
||||||
const childStickyBottom = ref(0);
|
const childStickyBottom = ref(0);
|
||||||
const parentStickyBottom = inject<Ref<number>>(CURRENT_STICKY_BOTTOM, ref(0));
|
const parentStickyBottom = inject(DI.currentStickyBottom, ref(0));
|
||||||
provide(CURRENT_STICKY_BOTTOM, childStickyBottom);
|
provide(DI.currentStickyBottom, childStickyBottom);
|
||||||
|
|
||||||
const calc = () => {
|
const calc = () => {
|
||||||
// コンポーネントが表示されてないけどKeepAliveで残ってる場合などは null になる
|
// コンポーネントが表示されてないけどKeepAliveで残ってる場合などは null になる
|
||||||
|
44
packages/frontend/src/components/global/PageWithHeader.vue
Normal file
44
packages/frontend/src/components/global/PageWithHeader.vue
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<!--
|
||||||
|
SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div :class="[$style.root, reversed ? '_pageScrollableReversed' : '_pageScrollable']">
|
||||||
|
<MkStickyContainer>
|
||||||
|
<template #header><MkPageHeader v-model:tab="tab" :actions="actions" :tabs="tabs"/></template>
|
||||||
|
<div :class="$style.body">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
<template #footer><slot name="footer"></slot></template>
|
||||||
|
</MkStickyContainer>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { PageHeaderItem } from '@/types/page-header.js';
|
||||||
|
import type { Tab } from './MkPageHeader.tabs.vue';
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<{
|
||||||
|
tabs?: Tab[];
|
||||||
|
actions?: PageHeaderItem[] | null;
|
||||||
|
thin?: boolean;
|
||||||
|
hideTitle?: boolean;
|
||||||
|
displayMyAvatar?: boolean;
|
||||||
|
reversed?: boolean;
|
||||||
|
}>(), {
|
||||||
|
tabs: () => ([] as Tab[]),
|
||||||
|
});
|
||||||
|
|
||||||
|
const tab = defineModel<string>('tab');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" module>
|
||||||
|
.root {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.body {
|
||||||
|
min-height: calc(100cqh - (var(--MI-stickyTop, 0px) + var(--MI-stickyBottom, 0px)));
|
||||||
|
}
|
||||||
|
</style>
|
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="_pageContainer" style="height: 100%;">
|
<div ref="rootEl" class="_pageContainer" :class="$style.root">
|
||||||
<KeepAlive :max="prefer.s.numberOfPageCache">
|
<KeepAlive :max="prefer.s.numberOfPageCache">
|
||||||
<Suspense :timeout="0">
|
<Suspense :timeout="0">
|
||||||
<component :is="currentPageComponent" :key="key" v-bind="Object.fromEntries(currentPageProps)"/>
|
<component :is="currentPageComponent" :key="key" v-bind="Object.fromEntries(currentPageProps)"/>
|
||||||
@@ -18,11 +18,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { inject, provide, ref, shallowRef } from 'vue';
|
import { inject, nextTick, onMounted, provide, ref, shallowRef, useTemplateRef } from 'vue';
|
||||||
import type { Router } from '@/router.js';
|
import type { Router } from '@/router.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import MkLoadingPage from '@/pages/_loading_.vue';
|
import MkLoadingPage from '@/pages/_loading_.vue';
|
||||||
import { DI } from '@/di.js';
|
import { DI } from '@/di.js';
|
||||||
|
import { randomId } from '@/utility/random-id.js';
|
||||||
|
import { deepEqual } from '@/utility/deep-equal.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
router?: Router;
|
router?: Router;
|
||||||
@@ -34,18 +36,76 @@ if (router == null) {
|
|||||||
throw new Error('no router provided');
|
throw new Error('no router provided');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const viewId = randomId();
|
||||||
|
provide(DI.viewId, viewId);
|
||||||
|
|
||||||
const currentDepth = inject(DI.routerCurrentDepth, 0);
|
const currentDepth = inject(DI.routerCurrentDepth, 0);
|
||||||
provide(DI.routerCurrentDepth, currentDepth + 1);
|
provide(DI.routerCurrentDepth, currentDepth + 1);
|
||||||
|
|
||||||
|
const rootEl = useTemplateRef('rootEl');
|
||||||
|
onMounted(() => {
|
||||||
|
rootEl.value.style.viewTransitionName = viewId; // view-transition-nameにcss varが使えないっぽいため直接代入
|
||||||
|
});
|
||||||
|
|
||||||
|
// view-transition-newなどの<pt-name-selector>にはcss varが使えず、v-bindできないため直接スタイルを生成
|
||||||
|
const viewTransitionStylesTag = window.document.createElement('style');
|
||||||
|
viewTransitionStylesTag.textContent = `
|
||||||
|
@keyframes ${viewId}-old {
|
||||||
|
to { transform: scale(0.95); opacity: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes ${viewId}-new {
|
||||||
|
from { transform: scale(0.95); opacity: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
::view-transition-old(${viewId}) {
|
||||||
|
animation-duration: 0.2s;
|
||||||
|
animation-name: ${viewId}-old;
|
||||||
|
}
|
||||||
|
|
||||||
|
::view-transition-new(${viewId}) {
|
||||||
|
animation-duration: 0.2s;
|
||||||
|
animation-name: ${viewId}-new;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
window.document.head.appendChild(viewTransitionStylesTag);
|
||||||
|
|
||||||
const current = router.current!;
|
const current = router.current!;
|
||||||
const currentPageComponent = shallowRef('component' in current.route ? current.route.component : MkLoadingPage);
|
const currentPageComponent = shallowRef('component' in current.route ? current.route.component : MkLoadingPage);
|
||||||
const currentPageProps = ref(current.props);
|
const currentPageProps = ref(current.props);
|
||||||
|
let currentRoutePath = current.route.path;
|
||||||
const key = ref(router.getCurrentFullPath());
|
const key = ref(router.getCurrentFullPath());
|
||||||
|
|
||||||
router.useListener('change', ({ resolved }) => {
|
router.useListener('change', ({ resolved }) => {
|
||||||
if (resolved == null || 'redirect' in resolved.route) return;
|
if (resolved == null || 'redirect' in resolved.route) return;
|
||||||
currentPageComponent.value = resolved.route.component;
|
if (resolved.route.path === currentRoutePath && deepEqual(resolved.props, currentPageProps.value)) return;
|
||||||
currentPageProps.value = resolved.props;
|
|
||||||
key.value = router.getCurrentFullPath();
|
function _() {
|
||||||
|
currentPageComponent.value = resolved.route.component;
|
||||||
|
currentPageProps.value = resolved.props;
|
||||||
|
key.value = router.getCurrentFullPath();
|
||||||
|
currentRoutePath = resolved.route.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
|
if (prefer.s.animation && window.document.startViewTransition) {
|
||||||
|
window.document.startViewTransition(() => new Promise((res) => {
|
||||||
|
_();
|
||||||
|
nextTick(() => {
|
||||||
|
res();
|
||||||
|
//setTimeout(res, 100);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
_();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" module>
|
||||||
|
.root {
|
||||||
|
height: 100%;
|
||||||
|
background-color: var(--MI_THEME-bg);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@@ -42,7 +42,7 @@ const highlighted = ref(props.markerId === searchMarkerId.value);
|
|||||||
|
|
||||||
function checkChildren() {
|
function checkChildren() {
|
||||||
if (props.children?.includes(searchMarkerId.value)) {
|
if (props.children?.includes(searchMarkerId.value)) {
|
||||||
const el = document.querySelector(`[data-in-app-search-marker-id="${searchMarkerId.value}"]`);
|
const el = window.document.querySelector(`[data-in-app-search-marker-id="${searchMarkerId.value}"]`);
|
||||||
highlighted.value = el == null;
|
highlighted.value = el == null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,6 +25,8 @@ import MkPageHeader from './global/MkPageHeader.vue';
|
|||||||
import MkSpacer from './global/MkSpacer.vue';
|
import MkSpacer from './global/MkSpacer.vue';
|
||||||
import MkStickyContainer from './global/MkStickyContainer.vue';
|
import MkStickyContainer from './global/MkStickyContainer.vue';
|
||||||
import MkLazy from './global/MkLazy.vue';
|
import MkLazy from './global/MkLazy.vue';
|
||||||
|
import PageWithHeader from './global/PageWithHeader.vue';
|
||||||
|
import PageWithAnimBg from './global/PageWithAnimBg.vue';
|
||||||
import SearchMarker from './global/SearchMarker.vue';
|
import SearchMarker from './global/SearchMarker.vue';
|
||||||
import SearchLabel from './global/SearchLabel.vue';
|
import SearchLabel from './global/SearchLabel.vue';
|
||||||
import SearchKeyword from './global/SearchKeyword.vue';
|
import SearchKeyword from './global/SearchKeyword.vue';
|
||||||
@@ -60,6 +62,8 @@ export const components = {
|
|||||||
MkSpacer: MkSpacer,
|
MkSpacer: MkSpacer,
|
||||||
MkStickyContainer: MkStickyContainer,
|
MkStickyContainer: MkStickyContainer,
|
||||||
MkLazy: MkLazy,
|
MkLazy: MkLazy,
|
||||||
|
PageWithHeader: PageWithHeader,
|
||||||
|
PageWithAnimBg: PageWithAnimBg,
|
||||||
SearchMarker: SearchMarker,
|
SearchMarker: SearchMarker,
|
||||||
SearchLabel: SearchLabel,
|
SearchLabel: SearchLabel,
|
||||||
SearchKeyword: SearchKeyword,
|
SearchKeyword: SearchKeyword,
|
||||||
@@ -89,6 +93,8 @@ declare module '@vue/runtime-core' {
|
|||||||
MkSpacer: typeof MkSpacer;
|
MkSpacer: typeof MkSpacer;
|
||||||
MkStickyContainer: typeof MkStickyContainer;
|
MkStickyContainer: typeof MkStickyContainer;
|
||||||
MkLazy: typeof MkLazy;
|
MkLazy: typeof MkLazy;
|
||||||
|
PageWithHeader: typeof PageWithHeader;
|
||||||
|
PageWithAnimBg: typeof PageWithAnimBg;
|
||||||
SearchMarker: typeof SearchMarker;
|
SearchMarker: typeof SearchMarker;
|
||||||
SearchLabel: typeof SearchLabel;
|
SearchLabel: typeof SearchLabel;
|
||||||
SearchKeyword: typeof SearchKeyword;
|
SearchKeyword: typeof SearchKeyword;
|
||||||
|
@@ -11,4 +11,7 @@ export const DI = {
|
|||||||
router: Symbol() as InjectionKey<Router>,
|
router: Symbol() as InjectionKey<Router>,
|
||||||
mock: Symbol() as InjectionKey<boolean>,
|
mock: Symbol() as InjectionKey<boolean>,
|
||||||
pageMetadata: Symbol() as InjectionKey<Ref<Record<string, any>>>,
|
pageMetadata: Symbol() as InjectionKey<Ref<Record<string, any>>>,
|
||||||
|
viewId: Symbol() as InjectionKey<string>,
|
||||||
|
currentStickyTop: Symbol() as InjectionKey<Ref<number>>,
|
||||||
|
currentStickyBottom: Symbol() as InjectionKey<Ref<number>>,
|
||||||
};
|
};
|
||||||
|
@@ -13,7 +13,7 @@ export default {
|
|||||||
el._keyHandler = makeHotkey(binding.value);
|
el._keyHandler = makeHotkey(binding.value);
|
||||||
|
|
||||||
if (el._hotkey_global) {
|
if (el._hotkey_global) {
|
||||||
document.addEventListener('keydown', el._keyHandler, { passive: false });
|
window.document.addEventListener('keydown', el._keyHandler, { passive: false });
|
||||||
} else {
|
} else {
|
||||||
el.addEventListener('keydown', el._keyHandler, { passive: false });
|
el.addEventListener('keydown', el._keyHandler, { passive: false });
|
||||||
}
|
}
|
||||||
@@ -21,7 +21,7 @@ export default {
|
|||||||
|
|
||||||
unmounted(el) {
|
unmounted(el) {
|
||||||
if (el._hotkey_global) {
|
if (el._hotkey_global) {
|
||||||
document.removeEventListener('keydown', el._keyHandler);
|
window.document.removeEventListener('keydown', el._keyHandler);
|
||||||
} else {
|
} else {
|
||||||
el.removeEventListener('keydown', el._keyHandler);
|
el.removeEventListener('keydown', el._keyHandler);
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,7 @@ export default {
|
|||||||
mounted(src, binding, vn) {
|
mounted(src, binding, vn) {
|
||||||
const parentBg = getBgColor(src.parentElement) ?? 'transparent';
|
const parentBg = getBgColor(src.parentElement) ?? 'transparent';
|
||||||
|
|
||||||
const myBg = getComputedStyle(document.documentElement).getPropertyValue('--MI_THEME-panel');
|
const myBg = getComputedStyle(window.document.documentElement).getPropertyValue('--MI_THEME-panel');
|
||||||
|
|
||||||
if (parentBg === myBg) {
|
if (parentBg === myBg) {
|
||||||
src.style.backgroundColor = 'var(--MI_THEME-bg)';
|
src.style.backgroundColor = 'var(--MI_THEME-bg)';
|
||||||
|
@@ -47,7 +47,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.show = () => {
|
self.show = () => {
|
||||||
if (!document.body.contains(el)) return;
|
if (!window.document.body.contains(el)) return;
|
||||||
if (self._close) return;
|
if (self._close) return;
|
||||||
if (self.text == null) return;
|
if (self.text == null) return;
|
||||||
|
|
||||||
|
@@ -31,7 +31,7 @@ export class UserPreview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private show() {
|
private show() {
|
||||||
if (!document.body.contains(this.el)) return;
|
if (!window.document.body.contains(this.el)) return;
|
||||||
if (this.promise) return;
|
if (this.promise) return;
|
||||||
|
|
||||||
const showing = ref(true);
|
const showing = ref(true);
|
||||||
@@ -58,7 +58,7 @@ export class UserPreview {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.checkTimer = window.setInterval(() => {
|
this.checkTimer = window.setInterval(() => {
|
||||||
if (!document.body.contains(this.el)) {
|
if (!window.document.body.contains(this.el)) {
|
||||||
window.clearTimeout(this.showTimer);
|
window.clearTimeout(this.showTimer);
|
||||||
window.clearTimeout(this.hideTimer);
|
window.clearTimeout(this.hideTimer);
|
||||||
this.close();
|
this.close();
|
||||||
|
@@ -12,7 +12,7 @@ import { DEFAULT_INFO_IMAGE_URL, DEFAULT_NOT_FOUND_IMAGE_URL, DEFAULT_SERVER_ERR
|
|||||||
// TODO: 他のタブと永続化されたstateを同期
|
// TODO: 他のタブと永続化されたstateを同期
|
||||||
|
|
||||||
//#region loader
|
//#region loader
|
||||||
const providedMetaEl = document.getElementById('misskey_meta');
|
const providedMetaEl = window.document.getElementById('misskey_meta');
|
||||||
|
|
||||||
let cachedMeta = miLocalStorage.getItem('instance') ? JSON.parse(miLocalStorage.getItem('instance')!) : null;
|
let cachedMeta = miLocalStorage.getItem('instance') ? JSON.parse(miLocalStorage.getItem('instance')!) : null;
|
||||||
let cachedAt = miLocalStorage.getItem('instanceCachedAt') ? parseInt(miLocalStorage.getItem('instanceCachedAt')!) : 0;
|
let cachedAt = miLocalStorage.getItem('instanceCachedAt') ? parseInt(miLocalStorage.getItem('instanceCachedAt')!) : 0;
|
||||||
|
@@ -320,7 +320,7 @@ export class Nirax<DEF extends RouteDef[]> extends EventEmitter<RouterEvents> {
|
|||||||
}
|
}
|
||||||
const res = this.navigate(fullPath);
|
const res = this.navigate(fullPath);
|
||||||
if (res.route.path === '/:(*)') {
|
if (res.route.path === '/:(*)') {
|
||||||
location.href = fullPath;
|
window.location.href = fullPath;
|
||||||
} else {
|
} else {
|
||||||
this.emit('push', {
|
this.emit('push', {
|
||||||
beforeFullPath,
|
beforeFullPath,
|
||||||
|
@@ -167,7 +167,7 @@ export const navbarItemDef = reactive({
|
|||||||
title: i18n.ts.reload,
|
title: i18n.ts.reload,
|
||||||
icon: 'ti ti-refresh',
|
icon: 'ti ti-refresh',
|
||||||
action: (ev) => {
|
action: (ev) => {
|
||||||
location.reload();
|
window.location.reload();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
profile: {
|
profile: {
|
||||||
|
@@ -21,10 +21,10 @@ import MkWaitingDialog from '@/components/MkWaitingDialog.vue';
|
|||||||
import MkPageWindow from '@/components/MkPageWindow.vue';
|
import MkPageWindow from '@/components/MkPageWindow.vue';
|
||||||
import MkToast from '@/components/MkToast.vue';
|
import MkToast from '@/components/MkToast.vue';
|
||||||
import MkDialog from '@/components/MkDialog.vue';
|
import MkDialog from '@/components/MkDialog.vue';
|
||||||
import MkPasswordDialog from '@/components/MkPasswordDialog.vue';
|
|
||||||
import MkEmojiPickerDialog from '@/components/MkEmojiPickerDialog.vue';
|
|
||||||
import MkPopupMenu from '@/components/MkPopupMenu.vue';
|
import MkPopupMenu from '@/components/MkPopupMenu.vue';
|
||||||
import MkContextMenu from '@/components/MkContextMenu.vue';
|
import MkContextMenu from '@/components/MkContextMenu.vue';
|
||||||
|
import type MkRoleSelectDialog_TypeReferenceOnly from '@/components/MkRoleSelectDialog.vue';
|
||||||
|
import type MkEmojiPickerDialog_TypeReferenceOnly from '@/components/MkEmojiPickerDialog.vue';
|
||||||
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
||||||
import { pleaseLogin } from '@/utility/please-login.js';
|
import { pleaseLogin } from '@/utility/please-login.js';
|
||||||
import { showMovedDialog } from '@/utility/show-moved-dialog.js';
|
import { showMovedDialog } from '@/utility/show-moved-dialog.js';
|
||||||
@@ -181,7 +181,7 @@ type EmitsExtractor<T> = {
|
|||||||
export function popup<T extends Component>(
|
export function popup<T extends Component>(
|
||||||
component: T,
|
component: T,
|
||||||
props: ComponentProps<T>,
|
props: ComponentProps<T>,
|
||||||
events: ComponentEmit<T> = {} as ComponentEmit<T>,
|
events: Partial<ComponentEmit<T>> = {},
|
||||||
): { dispose: () => void } {
|
): { dispose: () => void } {
|
||||||
markRaw(component);
|
markRaw(component);
|
||||||
|
|
||||||
@@ -460,7 +460,7 @@ export function authenticateDialog(): Promise<{
|
|||||||
canceled: false; result: { password: string; token: string | null; };
|
canceled: false; result: { password: string; token: string | null; };
|
||||||
}> {
|
}> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const { dispose } = popup(MkPasswordDialog, {}, {
|
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkPasswordDialog.vue')), {}, {
|
||||||
done: result => {
|
done: result => {
|
||||||
resolve(result ? { canceled: false, result } : { canceled: true, result: undefined });
|
resolve(result ? { canceled: false, result } : { canceled: true, result: undefined });
|
||||||
},
|
},
|
||||||
@@ -617,30 +617,26 @@ export async function selectDriveFolder(multiple: boolean): Promise<Misskey.enti
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function selectRole(params: {
|
export async function selectRole(params: ComponentProps<typeof MkRoleSelectDialog_TypeReferenceOnly>): Promise<
|
||||||
initialRoleIds?: string[],
|
|
||||||
title?: string,
|
|
||||||
infoMessage?: string,
|
|
||||||
publicOnly?: boolean,
|
|
||||||
}): Promise<
|
|
||||||
{ canceled: true; result: undefined; } |
|
{ canceled: true; result: undefined; } |
|
||||||
{ canceled: false; result: Misskey.entities.Role[] }
|
{ canceled: false; result: Misskey.entities.Role[] }
|
||||||
> {
|
> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
popup(defineAsyncComponent(() => import('@/components/MkRoleSelectDialog.vue')), params, {
|
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkRoleSelectDialog.vue')), params, {
|
||||||
done: roles => {
|
done: roles => {
|
||||||
resolve({ canceled: false, result: roles });
|
resolve({ canceled: false, result: roles });
|
||||||
},
|
},
|
||||||
close: () => {
|
close: () => {
|
||||||
resolve({ canceled: true, result: undefined });
|
resolve({ canceled: true, result: undefined });
|
||||||
},
|
},
|
||||||
}, 'dispose');
|
closed: () => dispose(),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function pickEmoji(src: HTMLElement, opts: ComponentProps<typeof MkEmojiPickerDialog>): Promise<string> {
|
export async function pickEmoji(src: HTMLElement, opts: ComponentProps<typeof MkEmojiPickerDialog_TypeReferenceOnly>): Promise<string> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const { dispose } = popup(MkEmojiPickerDialog, {
|
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkEmojiPickerDialog.vue')), {
|
||||||
src,
|
src,
|
||||||
...opts,
|
...opts,
|
||||||
}, {
|
}, {
|
||||||
@@ -675,7 +671,11 @@ export function popupMenu(items: MenuItem[], src?: HTMLElement | EventTarget | n
|
|||||||
width?: number;
|
width?: number;
|
||||||
onClosing?: () => void;
|
onClosing?: () => void;
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
let returnFocusTo = getHTMLElementOrNull(src) ?? getHTMLElementOrNull(document.activeElement);
|
if (!(src instanceof HTMLElement)) {
|
||||||
|
src = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let returnFocusTo = getHTMLElementOrNull(src) ?? getHTMLElementOrNull(window.document.activeElement);
|
||||||
return new Promise(resolve => nextTick(() => {
|
return new Promise(resolve => nextTick(() => {
|
||||||
const { dispose } = popup(MkPopupMenu, {
|
const { dispose } = popup(MkPopupMenu, {
|
||||||
items,
|
items,
|
||||||
@@ -704,7 +704,7 @@ export function contextMenu(items: MenuItem[], ev: MouseEvent): Promise<void> {
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
let returnFocusTo = getHTMLElementOrNull(ev.currentTarget ?? ev.target) ?? getHTMLElementOrNull(document.activeElement);
|
let returnFocusTo = getHTMLElementOrNull(ev.currentTarget ?? ev.target) ?? getHTMLElementOrNull(window.document.activeElement);
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
return new Promise(resolve => nextTick(() => {
|
return new Promise(resolve => nextTick(() => {
|
||||||
const { dispose } = popup(MkContextMenu, {
|
const { dispose } = popup(MkContextMenu, {
|
||||||
|
@@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<MkStickyContainer>
|
<PageWithHeader :actions="headerActions" :tabs="headerTabs">
|
||||||
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
|
||||||
<div style="overflow: clip;">
|
<div style="overflow: clip;">
|
||||||
<MkSpacer :contentMax="600" :marginMin="20">
|
<MkSpacer :contentMax="600" :marginMin="20">
|
||||||
<div class="_gaps_m znqjceqz">
|
<div class="_gaps_m znqjceqz">
|
||||||
@@ -130,7 +129,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</div>
|
</div>
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
</div>
|
</div>
|
||||||
</MkStickyContainer>
|
</PageWithHeader>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
@@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<MkStickyContainer>
|
<PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs">
|
||||||
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
|
|
||||||
<MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs">
|
<MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs">
|
||||||
<MkSpacer v-if="tab === 'overview'" :contentMax="600" :marginMin="20">
|
<MkSpacer v-if="tab === 'overview'" :contentMax="600" :marginMin="20">
|
||||||
<XOverview/>
|
<XOverview/>
|
||||||
@@ -20,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
<MkInstanceStats/>
|
<MkInstanceStats/>
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
</MkHorizontalSwipe>
|
</MkHorizontalSwipe>
|
||||||
</MkStickyContainer>
|
</PageWithHeader>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
@@ -4,12 +4,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<MkStickyContainer>
|
<PageWithHeader>
|
||||||
<template #header><MkPageHeader/></template>
|
|
||||||
<MkSpacer :contentMax="1200">
|
<MkSpacer :contentMax="1200">
|
||||||
<MkAchievements :user="$i"/>
|
<MkAchievements :user="$i"/>
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
</MkStickyContainer>
|
</PageWithHeader>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
@@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<MkStickyContainer>
|
<PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs">
|
||||||
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
|
|
||||||
<MkSpacer v-if="file" :contentMax="600" :marginMin="16" :marginMax="32">
|
<MkSpacer v-if="file" :contentMax="600" :marginMin="16" :marginMax="32">
|
||||||
<div v-if="tab === 'overview'" class="cxqhhsmd _gaps_m">
|
<div v-if="tab === 'overview'" class="cxqhhsmd _gaps_m">
|
||||||
<a class="thumbnail" :href="file.url" target="_blank">
|
<a class="thumbnail" :href="file.url" target="_blank">
|
||||||
@@ -67,7 +66,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</MkObjectView>
|
</MkObjectView>
|
||||||
</div>
|
</div>
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
</MkStickyContainer>
|
</PageWithHeader>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user