Compare commits
4 Commits
feat/bundl
...
l10n_devel
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
961badd01d | ||
|
|
1e4c49a9ab | ||
|
|
cc9d5bc2b5 | ||
|
|
144fabdead |
@@ -9,6 +9,8 @@ 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"
|
||||||
@@ -478,6 +480,8 @@ 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: "Zustimmen?"
|
lookupConfirm: "Bist du sicher, dass du das nachschlagen möchtest?"
|
||||||
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 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."
|
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."
|
||||||
_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 a recipient for reports"
|
createRecipient: "Add 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: "List of registered Emojis"
|
tabTitleList: "Registered emojis"
|
||||||
tabTitleRegister: "Emoji registration"
|
tabTitleRegister: "Emoji registration"
|
||||||
_list:
|
_list:
|
||||||
emojisNothing: "There are no registered Emojis."
|
emojisNothing: "There are no registered Emojis."
|
||||||
|
|||||||
@@ -698,6 +698,7 @@ userSaysSomethingAbout: "{name}님이 \"{word}\"를 언급했습니다."
|
|||||||
makeActive: "활성화"
|
makeActive: "활성화"
|
||||||
display: "보기"
|
display: "보기"
|
||||||
copy: "복사"
|
copy: "복사"
|
||||||
|
copiedToClipboard: "클립보드에 복사되었습니다."
|
||||||
metrics: "통계"
|
metrics: "통계"
|
||||||
overview: "요약"
|
overview: "요약"
|
||||||
logs: "로그"
|
logs: "로그"
|
||||||
@@ -1294,7 +1295,7 @@ thereAreNChanges: "{n}건 변경이 있습니다."
|
|||||||
signinWithPasskey: "패스키로 로그인"
|
signinWithPasskey: "패스키로 로그인"
|
||||||
unknownWebAuthnKey: "등록되지 않은 패스키입니다."
|
unknownWebAuthnKey: "등록되지 않은 패스키입니다."
|
||||||
passkeyVerificationFailed: "패스키 검증을 실패했습니다."
|
passkeyVerificationFailed: "패스키 검증을 실패했습니다."
|
||||||
passkeyVerificationSucceededButPasswordlessLoginDisabled: "패스키를 검증했으나, 비밀번호 없이 로그인하기가 꺼져 있습니다."
|
passkeyVerificationSucceededButPasswordlessLoginDisabled: "입력된 패스키는 정상적이나, 비밀번호 없이 로그인 하는 기능이 비활성화 되어있습니다."
|
||||||
messageToFollower: "팔로워에게 보낼 메시지"
|
messageToFollower: "팔로워에게 보낼 메시지"
|
||||||
target: "대상"
|
target: "대상"
|
||||||
testCaptchaWarning: "CAPTCHA를 테스트하기 위한 기능입니다. <strong>실제 환경에서는 사용하지 마세요.</strong>"
|
testCaptchaWarning: "CAPTCHA를 테스트하기 위한 기능입니다. <strong>실제 환경에서는 사용하지 마세요.</strong>"
|
||||||
@@ -1325,21 +1326,40 @@ 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: "이 디바이스를 식별할 이름을 설정해 주세요."
|
||||||
@@ -1363,6 +1383,7 @@ _accountSettings:
|
|||||||
makeNotesHiddenBefore: "과거 노트 비공개로 전환하기"
|
makeNotesHiddenBefore: "과거 노트 비공개로 전환하기"
|
||||||
makeNotesHiddenBeforeDescription: "이 기능이 활성화되어 있는 동안 설정한 날짜 및 시간보다 과거 또는 설정한 시간이 지난 노트는 본인만 볼 수 있게(비공개로 전환) 됩니다. 비활성화하면 노트의 공개 상태도 원래대로 돌아갑니다."
|
makeNotesHiddenBeforeDescription: "이 기능이 활성화되어 있는 동안 설정한 날짜 및 시간보다 과거 또는 설정한 시간이 지난 노트는 본인만 볼 수 있게(비공개로 전환) 됩니다. 비활성화하면 노트의 공개 상태도 원래대로 돌아갑니다."
|
||||||
mayNotEffectForFederatedNotes: "원격 서버에 연합된 노트에는 효과가 없을 수도 있습니다."
|
mayNotEffectForFederatedNotes: "원격 서버에 연합된 노트에는 효과가 없을 수도 있습니다."
|
||||||
|
mayNotEffectSomeSituations: "여기서 설정하는 제한은 모더레이션이나 리모트 서버에서 볼 때 등 일부 환경에서는 적용되지 않을 수도 있습니다."
|
||||||
notesHavePassedSpecifiedPeriod: "지정한 시간이 경과된 노트"
|
notesHavePassedSpecifiedPeriod: "지정한 시간이 경과된 노트"
|
||||||
notesOlderThanSpecifiedDateAndTime: "지정된 날짜 및 시간 이전의 노트"
|
notesOlderThanSpecifiedDateAndTime: "지정된 날짜 및 시간 이전의 노트"
|
||||||
_abuseUserReport:
|
_abuseUserReport:
|
||||||
@@ -2503,6 +2524,7 @@ _notification:
|
|||||||
achievementEarned: "도전 과제 획득"
|
achievementEarned: "도전 과제 획득"
|
||||||
exportCompleted: "추출을 성공함"
|
exportCompleted: "추출을 성공함"
|
||||||
login: "로그인"
|
login: "로그인"
|
||||||
|
createToken: "액세스 토큰 만들기"
|
||||||
test: "알림 테스트"
|
test: "알림 테스트"
|
||||||
app: "연동된 앱을 통한 알림"
|
app: "연동된 앱을 통한 알림"
|
||||||
_actions:
|
_actions:
|
||||||
@@ -2530,6 +2552,7 @@ _deck:
|
|||||||
useSimpleUiForNonRootPages: "루트 이외의 페이지로 접속한 경우 UI 간략화하기"
|
useSimpleUiForNonRootPages: "루트 이외의 페이지로 접속한 경우 UI 간략화하기"
|
||||||
usedAsMinWidthWhenFlexible: "'폭 자동 조정'이 활성화된 경우 최소 폭으로 사용됩니다"
|
usedAsMinWidthWhenFlexible: "'폭 자동 조정'이 활성화된 경우 최소 폭으로 사용됩니다"
|
||||||
flexible: "폭 자동 조정"
|
flexible: "폭 자동 조정"
|
||||||
|
enableSyncBetweenDevicesForProfiles: "프로파일 정보의 디바이스 간 동기화를 활성화"
|
||||||
_columns:
|
_columns:
|
||||||
main: "메인"
|
main: "메인"
|
||||||
widgets: "위젯"
|
widgets: "위젯"
|
||||||
|
|||||||
@@ -235,7 +235,6 @@
|
|||||||
"jest-mock": "29.7.0",
|
"jest-mock": "29.7.0",
|
||||||
"nodemon": "3.1.9",
|
"nodemon": "3.1.9",
|
||||||
"pid-port": "1.0.2",
|
"pid-port": "1.0.2",
|
||||||
"simple-oauth2": "5.1.0",
|
"simple-oauth2": "5.1.0"
|
||||||
"vite": "6.2.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,13 +5,10 @@
|
|||||||
|
|
||||||
import * as fs from 'node:fs';
|
import * as fs from 'node:fs';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { dirname, join, resolve } from 'node:path';
|
import { dirname, resolve } from 'node:path';
|
||||||
import * as yaml from 'js-yaml';
|
import * as yaml from 'js-yaml';
|
||||||
import * as Sentry from '@sentry/node';
|
import * as Sentry from '@sentry/node';
|
||||||
import locale from '../../../locales/index.js';
|
|
||||||
import type { RedisOptions } from 'ioredis';
|
import type { RedisOptions } from 'ioredis';
|
||||||
import type { Manifest, ManifestChunk } from 'vite';
|
|
||||||
import type { ILocale } from '../../../locales/index.js';
|
|
||||||
|
|
||||||
type RedisOptionsSource = Partial<RedisOptions> & {
|
type RedisOptionsSource = Partial<RedisOptions> & {
|
||||||
host: string;
|
host: string;
|
||||||
@@ -188,12 +185,9 @@ export type Config = {
|
|||||||
authUrl: string;
|
authUrl: string;
|
||||||
driveUrl: string;
|
driveUrl: string;
|
||||||
userAgent: string;
|
userAgent: string;
|
||||||
localeEntries: Record<string, string>;
|
frontendEntry: string;
|
||||||
errorLocaleMessages: Record<string, ILocale>;
|
|
||||||
configEntry: ManifestChunk;
|
|
||||||
frontendEntry: ManifestChunk;
|
|
||||||
frontendManifestExists: boolean;
|
frontendManifestExists: boolean;
|
||||||
frontendEmbedEntry: ManifestChunk;
|
frontendEmbedEntry: string;
|
||||||
frontendEmbedManifestExists: boolean;
|
frontendEmbedManifestExists: boolean;
|
||||||
mediaProxy: string;
|
mediaProxy: string;
|
||||||
externalMediaProxyEnabled: boolean;
|
externalMediaProxyEnabled: boolean;
|
||||||
@@ -235,23 +229,12 @@ export function loadConfig(): Config {
|
|||||||
|
|
||||||
const frontendManifestExists = fs.existsSync(_dirname + '/../../../built/_frontend_vite_/manifest.json');
|
const frontendManifestExists = fs.existsSync(_dirname + '/../../../built/_frontend_vite_/manifest.json');
|
||||||
const frontendEmbedManifestExists = fs.existsSync(_dirname + '/../../../built/_frontend_embed_vite_/manifest.json');
|
const frontendEmbedManifestExists = fs.existsSync(_dirname + '/../../../built/_frontend_embed_vite_/manifest.json');
|
||||||
const frontendManifest: Manifest = frontendManifestExists
|
const frontendManifest = frontendManifestExists ?
|
||||||
? JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_frontend_vite_/manifest.json`, 'utf-8'))
|
JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_frontend_vite_/manifest.json`, 'utf-8'))
|
||||||
: Object.entries(locale).reduce<Record<string, ManifestChunk>>((a, [k]) => {
|
: { 'src/_boot_.ts': { file: 'src/_boot_.ts' } };
|
||||||
a[`locale:${k}`] = { file: `locale:${k}` };
|
const frontendEmbedManifest = frontendEmbedManifestExists ?
|
||||||
return a;
|
JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_frontend_embed_vite_/manifest.json`, 'utf-8'))
|
||||||
}, {
|
: { 'src/boot.ts': { file: 'src/boot.ts' } };
|
||||||
'src/_boot_.ts': { file: 'src/_boot_.ts' },
|
|
||||||
'../frontend-shared/js/config.ts': { file: join('@fs', _dirname.slice(1), '../../frontend-shared/js/config.ts') },
|
|
||||||
});
|
|
||||||
const frontendEmbedManifest: Manifest = frontendEmbedManifestExists
|
|
||||||
? JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_frontend_embed_vite_/manifest.json`, 'utf-8'))
|
|
||||||
: Object.entries(locale).reduce<Record<string, ManifestChunk>>((a, [k]) => {
|
|
||||||
a[`locale:${k}`] = { file: `locale:${k}` };
|
|
||||||
return a;
|
|
||||||
}, {
|
|
||||||
'src/boot.ts': { file: 'src/boot.ts' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const config = yaml.load(fs.readFileSync(path, 'utf-8')) as Source;
|
const config = yaml.load(fs.readFileSync(path, 'utf-8')) as Source;
|
||||||
|
|
||||||
@@ -327,20 +310,6 @@ export function loadConfig(): Config {
|
|||||||
config.videoThumbnailGenerator.endsWith('/') ? config.videoThumbnailGenerator.substring(0, config.videoThumbnailGenerator.length - 1) : config.videoThumbnailGenerator
|
config.videoThumbnailGenerator.endsWith('/') ? config.videoThumbnailGenerator.substring(0, config.videoThumbnailGenerator.length - 1) : config.videoThumbnailGenerator
|
||||||
: null,
|
: null,
|
||||||
userAgent: `Misskey/${version} (${config.url})`,
|
userAgent: `Misskey/${version} (${config.url})`,
|
||||||
localeEntries: Object.entries<ManifestChunk>(frontendManifest).reduce<Record<string, string>>((a, [k, v]) => {
|
|
||||||
if (k.startsWith('locale:')) {
|
|
||||||
a[k.slice('locale:'.length)] = v.file;
|
|
||||||
}
|
|
||||||
return a;
|
|
||||||
}, {}),
|
|
||||||
errorLocaleMessages: Object.entries(locale).reduce<Record<string, ILocale>>((a, [k, v]) => {
|
|
||||||
a[k] = {
|
|
||||||
_bootErrors: v._bootErrors,
|
|
||||||
reload: v.reload,
|
|
||||||
};
|
|
||||||
return a;
|
|
||||||
}, {}),
|
|
||||||
configEntry: frontendManifest['../frontend-shared/js/config.ts'],
|
|
||||||
frontendEntry: frontendManifest['src/_boot_.ts'],
|
frontendEntry: frontendManifest['src/_boot_.ts'],
|
||||||
frontendManifestExists: frontendManifestExists,
|
frontendManifestExists: frontendManifestExists,
|
||||||
frontendEmbedEntry: frontendEmbedManifest['src/boot.ts'],
|
frontendEmbedEntry: frontendEmbedManifest['src/boot.ts'],
|
||||||
|
|||||||
@@ -32,9 +32,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
//#region Detect language & fetch translations
|
//#region Detect language & fetch translations
|
||||||
|
if (!localStorage.hasOwnProperty('locale')) {
|
||||||
const supportedLangs = LANGS;
|
const supportedLangs = LANGS;
|
||||||
let lang = localStorage.getItem('lang');
|
let lang = localStorage.getItem('lang');
|
||||||
if (!supportedLangs.includes(lang)) {
|
if (lang == null || !supportedLangs.includes(lang)) {
|
||||||
if (supportedLangs.includes(navigator.language)) {
|
if (supportedLangs.includes(navigator.language)) {
|
||||||
lang = navigator.language;
|
lang = navigator.language;
|
||||||
} else {
|
} else {
|
||||||
@@ -45,11 +46,42 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await import(`/vite/${LOCALES[lang]}`)
|
const metaRes = await window.fetch('/api/meta', {
|
||||||
.catch(async e => {
|
method: 'POST',
|
||||||
console.error(e);
|
body: JSON.stringify({}),
|
||||||
renderError('LOCALE_FETCH', e);
|
credentials: 'omit',
|
||||||
|
cache: 'no-cache',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
if (metaRes.status !== 200) {
|
||||||
|
renderError('META_FETCH');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const meta = await metaRes.json();
|
||||||
|
const v = meta.version;
|
||||||
|
if (v == null) {
|
||||||
|
renderError('META_FETCH_V');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for https://github.com/misskey-dev/misskey/issues/10202
|
||||||
|
if (lang == null || lang.toString == null || lang.toString() === 'null') {
|
||||||
|
console.error('invalid lang value detected!!!', typeof lang, lang);
|
||||||
|
lang = 'en-US';
|
||||||
|
}
|
||||||
|
|
||||||
|
const localRes = await window.fetch(`/assets/locales/${lang}.${v}.json`);
|
||||||
|
if (localRes.status === 200) {
|
||||||
|
localStorage.setItem('lang', lang);
|
||||||
|
localStorage.setItem('locale', await localRes.text());
|
||||||
|
localStorage.setItem('localeVersion', v);
|
||||||
|
} else {
|
||||||
|
renderError('LOCALE_FETCH');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region Script
|
//#region Script
|
||||||
@@ -83,21 +115,10 @@
|
|||||||
await new Promise(resolve => window.addEventListener('DOMContentLoaded', resolve));
|
await new Promise(resolve => window.addEventListener('DOMContentLoaded', resolve));
|
||||||
}
|
}
|
||||||
|
|
||||||
const supportedLangs = LANGS;
|
const locale = JSON.parse(localStorage.getItem('locale') || '{}');
|
||||||
let lang = localStorage.getItem('lang');
|
|
||||||
if (!supportedLangs.includes(lang)) {
|
|
||||||
if (supportedLangs.includes(navigator.language)) {
|
|
||||||
lang = navigator.language;
|
|
||||||
} else {
|
|
||||||
lang = supportedLangs.find(x => x.split('-')[0] === navigator.language);
|
|
||||||
|
|
||||||
// Fallback
|
const title = locale?._bootErrors?.title || 'Failed to initialize Misskey';
|
||||||
if (lang == null) lang = 'en-US';
|
const reload = locale?.reload || 'Reload';
|
||||||
}
|
|
||||||
}
|
|
||||||
const { locale } = await import(`/vite/${CONFIG_ENTRY}`).catch(() => ({ locale: {} }));
|
|
||||||
const title = locale._bootErrors.title;
|
|
||||||
const reload = locale.reload;
|
|
||||||
|
|
||||||
document.body.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" /><path d="M12 9v4" /><path d="M12 16v.01" /></svg>
|
document.body.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" /><path d="M12 9v4" /><path d="M12 16v.01" /></svg>
|
||||||
<div class="message">${title}</div>
|
<div class="message">${title}</div>
|
||||||
|
|||||||
@@ -23,9 +23,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
//#region Detect language & fetch translations
|
//#region Detect language & fetch translations
|
||||||
|
if (!localStorage.hasOwnProperty('locale')) {
|
||||||
const supportedLangs = LANGS;
|
const supportedLangs = LANGS;
|
||||||
let lang = localStorage.getItem('lang');
|
let lang = localStorage.getItem('lang');
|
||||||
if (!supportedLangs.includes(lang)) {
|
if (lang == null || !supportedLangs.includes(lang)) {
|
||||||
if (supportedLangs.includes(navigator.language)) {
|
if (supportedLangs.includes(navigator.language)) {
|
||||||
lang = navigator.language;
|
lang = navigator.language;
|
||||||
} else {
|
} else {
|
||||||
@@ -36,11 +37,42 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await import(`/vite/${LOCALES[lang]}`)
|
const metaRes = await window.fetch('/api/meta', {
|
||||||
.catch(async e => {
|
method: 'POST',
|
||||||
console.error(e);
|
body: JSON.stringify({}),
|
||||||
renderError('LOCALE_FETCH', e);
|
credentials: 'omit',
|
||||||
|
cache: 'no-cache',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
if (metaRes.status !== 200) {
|
||||||
|
renderError('META_FETCH');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const meta = await metaRes.json();
|
||||||
|
const v = meta.version;
|
||||||
|
if (v == null) {
|
||||||
|
renderError('META_FETCH_V');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for https://github.com/misskey-dev/misskey/issues/10202
|
||||||
|
if (lang == null || lang.toString == null || lang.toString() === 'null') {
|
||||||
|
console.error('invalid lang value detected!!!', typeof lang, lang);
|
||||||
|
lang = 'en-US';
|
||||||
|
}
|
||||||
|
|
||||||
|
const localRes = await window.fetch(`/assets/locales/${lang}.${v}.json`);
|
||||||
|
if (localRes.status === 200) {
|
||||||
|
localStorage.setItem('lang', lang);
|
||||||
|
localStorage.setItem('locale', await localRes.text());
|
||||||
|
localStorage.setItem('localeVersion', v);
|
||||||
|
} else {
|
||||||
|
renderError('LOCALE_FETCH');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region Script
|
//#region Script
|
||||||
@@ -119,25 +151,21 @@
|
|||||||
await new Promise(resolve => window.addEventListener('DOMContentLoaded', resolve));
|
await new Promise(resolve => window.addEventListener('DOMContentLoaded', resolve));
|
||||||
}
|
}
|
||||||
|
|
||||||
const supportedLangs = LANGS;
|
const locale = JSON.parse(localStorage.getItem('locale') || '{}');
|
||||||
let lang = localStorage.getItem('lang');
|
|
||||||
if (!supportedLangs.includes(lang)) {
|
|
||||||
if (supportedLangs.includes(navigator.language)) {
|
|
||||||
lang = navigator.language;
|
|
||||||
} else {
|
|
||||||
lang = supportedLangs.find(x => x.split('-')[0] === navigator.language);
|
|
||||||
|
|
||||||
// Fallback
|
const messages = Object.assign({
|
||||||
if (lang == null) lang = 'en-US';
|
title: 'Failed to initialize Misskey',
|
||||||
}
|
solution: 'The following actions may solve the problem.',
|
||||||
}
|
solution1: 'Update your os and browser',
|
||||||
const { locale } = await import(`/vite/${CONFIG_ENTRY}`).catch(() => ({
|
solution2: 'Disable an adblocker',
|
||||||
locale: {
|
solution3: 'Clear the browser cache',
|
||||||
_bootErrors: {},
|
solution4: '(Tor Browser) Set dom.webaudio.enabled to true',
|
||||||
},
|
otherOption: 'Other options',
|
||||||
}));
|
otherOption1: 'Clear preferences and cache',
|
||||||
const messages = locale._bootErrors;
|
otherOption2: 'Start the simple client',
|
||||||
const reload = locale.reload;
|
otherOption3: 'Start the repair tool',
|
||||||
|
}, locale?._bootErrors || {});
|
||||||
|
const reload = locale?.reload || 'Reload';
|
||||||
|
|
||||||
let errorsElement = document.getElementById('errors');
|
let errorsElement = document.getElementById('errors');
|
||||||
|
|
||||||
|
|||||||
@@ -6,22 +6,23 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
(() => {
|
(() => {
|
||||||
document.addEventListener('DOMContentLoaded', async () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
const supportedLangs = LANGS;
|
const locale = JSON.parse(localStorage.getItem('locale') || '{}');
|
||||||
let lang = localStorage.getItem('lang');
|
|
||||||
if (!supportedLangs.includes(lang)) {
|
|
||||||
if (supportedLangs.includes(navigator.language)) {
|
|
||||||
lang = navigator.language;
|
|
||||||
} else {
|
|
||||||
lang = supportedLangs.find(x => x.split('-')[0] === navigator.language);
|
|
||||||
|
|
||||||
// Fallback
|
const messages = Object.assign({
|
||||||
if (lang == null) lang = 'en-US';
|
title: 'Failed to initialize Misskey',
|
||||||
}
|
serverError: 'If reloading after a period of time does not resolve the problem, contact the server administrator with the following ERROR ID.',
|
||||||
}
|
solution: 'The following actions may solve the problem.',
|
||||||
const locale = ERROR_MESSAGES[lang];
|
solution1: 'Update your os and browser',
|
||||||
const messages = locale._bootErrors;
|
solution2: 'Disable an adblocker',
|
||||||
const reload = locale.reload;
|
solution3: 'Clear the browser cache',
|
||||||
|
solution4: '(Tor Browser) Set dom.webaudio.enabled to true',
|
||||||
|
otherOption: 'Other options',
|
||||||
|
otherOption1: 'Clear preferences and cache',
|
||||||
|
otherOption2: 'Start the simple client',
|
||||||
|
otherOption3: 'Start the repair tool',
|
||||||
|
}, locale?._bootErrors || {});
|
||||||
|
const reload = locale?.reload || 'Reload';
|
||||||
|
|
||||||
const reloadEls = document.querySelectorAll('[data-i18n-reload]');
|
const reloadEls = document.querySelectorAll('[data-i18n-reload]');
|
||||||
for (const el of reloadEls) {
|
for (const el of reloadEls) {
|
||||||
|
|||||||
@@ -41,8 +41,6 @@ html(class='embed')
|
|||||||
script.
|
script.
|
||||||
var VERSION = "#{version}";
|
var VERSION = "#{version}";
|
||||||
var CLIENT_ENTRY = "#{entry.file}";
|
var CLIENT_ENTRY = "#{entry.file}";
|
||||||
var CONFIG_ENTRY = "#{config.configEntry.file}";
|
|
||||||
var LOCALES = JSON.parse(`!{JSON.stringify(config.localeEntries)}`);
|
|
||||||
|
|
||||||
script(type='application/json' id='misskey_meta' data-generated-at=now)
|
script(type='application/json' id='misskey_meta' data-generated-at=now)
|
||||||
!= metaJson
|
!= metaJson
|
||||||
|
|||||||
@@ -70,8 +70,6 @@ html
|
|||||||
script.
|
script.
|
||||||
var VERSION = "#{version}";
|
var VERSION = "#{version}";
|
||||||
var CLIENT_ENTRY = "#{entry.file}";
|
var CLIENT_ENTRY = "#{entry.file}";
|
||||||
var CONFIG_ENTRY = "#{config.configEntry.file}";
|
|
||||||
var LOCALES = JSON.parse(`!{JSON.stringify(config.localeEntries)}`);
|
|
||||||
|
|
||||||
script(type='application/json' id='misskey_meta' data-generated-at=now)
|
script(type='application/json' id='misskey_meta' data-generated-at=now)
|
||||||
!= metaJson
|
!= metaJson
|
||||||
|
|||||||
@@ -27,9 +27,6 @@ html
|
|||||||
style
|
style
|
||||||
include ../error.css
|
include ../error.css
|
||||||
|
|
||||||
script.
|
|
||||||
var ERROR_MESSAGES = JSON.parse(`!{JSON.stringify(config.errorLocaleMessages)}`);
|
|
||||||
|
|
||||||
script
|
script
|
||||||
include ../error.js
|
include ../error.js
|
||||||
|
|
||||||
|
|||||||
@@ -13,17 +13,18 @@ import { createApp, defineAsyncComponent } from 'vue';
|
|||||||
import defaultLightTheme from '@@/themes/l-light.json5';
|
import defaultLightTheme from '@@/themes/l-light.json5';
|
||||||
import defaultDarkTheme from '@@/themes/d-dark.json5';
|
import defaultDarkTheme from '@@/themes/d-dark.json5';
|
||||||
import { MediaProxy } from '@@/js/media-proxy.js';
|
import { MediaProxy } from '@@/js/media-proxy.js';
|
||||||
import { url, version, locale, lang, updateLocale } from '@@/js/config.js';
|
|
||||||
import { parseEmbedParams } from '@@/js/embed-page.js';
|
|
||||||
import type { Theme } from '@/theme.js';
|
|
||||||
import { applyTheme, assertIsTheme } from '@/theme.js';
|
import { applyTheme, assertIsTheme } from '@/theme.js';
|
||||||
import { fetchCustomEmojis } from '@/custom-emojis.js';
|
import { fetchCustomEmojis } from '@/custom-emojis.js';
|
||||||
import { DI } from '@/di.js';
|
import { DI } from '@/di.js';
|
||||||
import { serverMetadata } from '@/server-metadata.js';
|
import { serverMetadata } from '@/server-metadata.js';
|
||||||
|
import { url, version, locale, lang, updateLocale } from '@@/js/config.js';
|
||||||
|
import { parseEmbedParams } from '@@/js/embed-page.js';
|
||||||
import { postMessageToParentWindow, setIframeId } from '@/post-message.js';
|
import { postMessageToParentWindow, setIframeId } from '@/post-message.js';
|
||||||
import { serverContext } from '@/server-context.js';
|
import { serverContext } from '@/server-context.js';
|
||||||
import { i18n, updateI18n } from '@/i18n.js';
|
import { i18n, updateI18n } from '@/i18n.js';
|
||||||
|
|
||||||
|
import type { Theme } from '@/theme.js';
|
||||||
|
|
||||||
console.log('Misskey Embed');
|
console.log('Misskey Embed');
|
||||||
|
|
||||||
//#region Embedパラメータの取得・パース
|
//#region Embedパラメータの取得・パース
|
||||||
@@ -70,6 +71,22 @@ if (embedParams.colorMode === 'dark') {
|
|||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
//#region Detect language & fetch translations
|
||||||
|
const localeVersion = localStorage.getItem('localeVersion');
|
||||||
|
const localeOutdated = (localeVersion == null || localeVersion !== version || locale == null);
|
||||||
|
if (localeOutdated) {
|
||||||
|
const res = await window.fetch(`/assets/locales/${lang}.${version}.json`);
|
||||||
|
if (res.status === 200) {
|
||||||
|
const newLocale = await res.text();
|
||||||
|
const parsedNewLocale = JSON.parse(newLocale);
|
||||||
|
localStorage.setItem('locale', newLocale);
|
||||||
|
localStorage.setItem('localeVersion', version);
|
||||||
|
updateLocale(parsedNewLocale);
|
||||||
|
updateI18n(parsedNewLocale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
// サイズの制限
|
// サイズの制限
|
||||||
document.documentElement.style.maxWidth = '500px';
|
document.documentElement.style.maxWidth = '500px';
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ export const apiUrl = location.origin + '/api';
|
|||||||
export const wsOrigin = location.origin;
|
export const wsOrigin = location.origin;
|
||||||
export const lang = localStorage.getItem('lang') ?? 'en-US';
|
export const lang = localStorage.getItem('lang') ?? 'en-US';
|
||||||
export const langs = _LANGS_;
|
export const langs = _LANGS_;
|
||||||
export let locale: Locale;
|
const preParseLocale = localStorage.getItem('locale');
|
||||||
|
export let locale: Locale = preParseLocale ? JSON.parse(preParseLocale) : null;
|
||||||
export const version = _VERSION_;
|
export const version = _VERSION_;
|
||||||
export const instanceName = (siteName === 'Misskey' || siteName == null) ? host : siteName;
|
export const instanceName = (siteName === 'Misskey' || siteName == null) ? host : siteName;
|
||||||
export const ui = localStorage.getItem('ui');
|
export const ui = localStorage.getItem('ui');
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ export function imageDataUrl(options?: {
|
|||||||
alpha?: number,
|
alpha?: number,
|
||||||
}
|
}
|
||||||
}, seed?: string): string {
|
}, seed?: string): string {
|
||||||
const canvas = window.document.createElement('canvas');
|
const canvas = 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[window.document.documentElement.dataset.misskeyTheme];
|
const theme = themes[document.documentElement.dataset.misskeyTheme];
|
||||||
if (theme) {
|
if (theme) {
|
||||||
applyTheme(themes[window.document.documentElement.dataset.misskeyTheme]);
|
applyTheme(themes[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(window.document.documentElement, {
|
observer.observe(document.documentElement, {
|
||||||
attributes: true,
|
attributes: true,
|
||||||
attributeFilter: ['data-misskey-theme'],
|
attributeFilter: ['data-misskey-theme'],
|
||||||
});
|
});
|
||||||
@@ -55,6 +55,7 @@ function initLocalStorage() {
|
|||||||
...userDetailed(),
|
...userDetailed(),
|
||||||
policies: {},
|
policies: {},
|
||||||
}));
|
}));
|
||||||
|
localStorage.setItem('locale', JSON.stringify(locale));
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize({
|
initialize({
|
||||||
@@ -69,17 +70,13 @@ queueMicrotask(() => {
|
|||||||
import('../src/theme.js'),
|
import('../src/theme.js'),
|
||||||
import('../src/preferences.js'),
|
import('../src/preferences.js'),
|
||||||
import('../src/os.js'),
|
import('../src/os.js'),
|
||||||
import('../src/i18n.js'),
|
]).then(([{ default: components }, { default: directives }, { default: widgets }, { applyTheme }, { prefer }, os]) => {
|
||||||
import('../../frontend-shared/js/config.js'),
|
|
||||||
]).then(([{ default: components }, { default: directives }, { default: widgets }, { applyTheme }, { prefer }, os, { updateI18n }, { updateLocale }]) => {
|
|
||||||
setup((app) => {
|
setup((app) => {
|
||||||
moduleInitialized = true;
|
moduleInitialized = true;
|
||||||
if (app[appInitialized]) {
|
if (app[appInitialized]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
app[appInitialized] = true;
|
app[appInitialized] = true;
|
||||||
updateLocale(locale);
|
|
||||||
updateI18n(locale);
|
|
||||||
loadTheme(applyTheme);
|
loadTheme(applyTheme);
|
||||||
components(app);
|
components(app);
|
||||||
directives(app);
|
directives(app);
|
||||||
|
|||||||
@@ -56,9 +56,7 @@ 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 紛らわしい
|
||||||
// document ... window.documentと衝突 or 紛らわしい
|
'id-denylist': ['warn', 'window', 'e', 'close', 'open', 'fetch', 'location'],
|
||||||
// history ... window.historyと衝突 or 紛らわしい
|
|
||||||
'id-denylist': ['warn', 'window', 'e', 'close', 'open', 'fetch', 'location', 'document', 'history'],
|
|
||||||
'no-restricted-globals': [
|
'no-restricted-globals': [
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
@@ -77,18 +75,10 @@ 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', {
|
||||||
|
|||||||
@@ -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 => window.location.pathname === i || window.location.pathname.startsWith(i + '/'))) {
|
if (subBootPaths.some(i => location.pathname === i || 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で指定された先に移動
|
||||||
window.location.href = redirect;
|
location.href = redirect;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,29 +78,45 @@ export async function common(createVue: () => App<Element>) {
|
|||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
//#region Detect language & fetch translations
|
||||||
|
const localeVersion = miLocalStorage.getItem('localeVersion');
|
||||||
|
const localeOutdated = (localeVersion == null || localeVersion !== version || locale == null);
|
||||||
|
if (localeOutdated) {
|
||||||
|
const res = await window.fetch(`/assets/locales/${lang}.${version}.json`);
|
||||||
|
if (res.status === 200) {
|
||||||
|
const newLocale = await res.text();
|
||||||
|
const parsedNewLocale = JSON.parse(newLocale);
|
||||||
|
miLocalStorage.setItem('locale', newLocale);
|
||||||
|
miLocalStorage.setItem('localeVersion', version);
|
||||||
|
updateLocale(parsedNewLocale);
|
||||||
|
updateI18n(parsedNewLocale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
// タッチデバイスでCSSの:hoverを機能させる
|
// タッチデバイスでCSSの:hoverを機能させる
|
||||||
window.document.addEventListener('touchend', () => {}, { passive: true });
|
document.addEventListener('touchend', () => {}, { passive: true });
|
||||||
|
|
||||||
// URLに#pswpを含む場合は取り除く
|
// URLに#pswpを含む場合は取り除く
|
||||||
if (window.location.hash === '#pswp') {
|
if (location.hash === '#pswp') {
|
||||||
window.history.replaceState(null, '', window.location.href.replace('#pswp', ''));
|
history.replaceState(null, '', location.href.replace('#pswp', ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 一斉リロード
|
// 一斉リロード
|
||||||
reloadChannel.addEventListener('message', path => {
|
reloadChannel.addEventListener('message', path => {
|
||||||
if (path !== null) window.location.href = path;
|
if (path !== null) location.href = path;
|
||||||
else window.location.reload();
|
else 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 = window.document.getElementsByName('viewport').item(0);
|
const viewport = 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 = window.document.documentElement;
|
const html = document.documentElement;
|
||||||
html.setAttribute('lang', lang);
|
html.setAttribute('lang', lang);
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
@@ -114,11 +130,11 @@ export async function common(createVue: () => App<Element>) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
//#region loginId
|
//#region loginId
|
||||||
const params = new URLSearchParams(window.location.search);
|
const params = new URLSearchParams(location.search);
|
||||||
const loginId = params.get('loginId');
|
const loginId = params.get('loginId');
|
||||||
|
|
||||||
if (loginId) {
|
if (loginId) {
|
||||||
const target = getUrlWithoutLoginId(window.location.href);
|
const target = getUrlWithoutLoginId(location.href);
|
||||||
|
|
||||||
if (!$i || $i.id !== loginId) {
|
if (!$i || $i.id !== loginId) {
|
||||||
const account = await getAccountFromId(loginId);
|
const account = await getAccountFromId(loginId);
|
||||||
@@ -127,7 +143,7 @@ export async function common(createVue: () => App<Element>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.history.replaceState({ misskey: 'loginId' }, '', target);
|
history.replaceState({ misskey: 'loginId' }, '', target);
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
@@ -139,7 +155,7 @@ export async function common(createVue: () => App<Element>) {
|
|||||||
);
|
);
|
||||||
}, { immediate: miLocalStorage.getItem('theme') == null });
|
}, { immediate: miLocalStorage.getItem('theme') == null });
|
||||||
|
|
||||||
window.document.documentElement.dataset.colorScheme = store.s.darkMode ? 'dark' : 'light';
|
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');
|
||||||
@@ -185,20 +201,20 @@ export async function common(createVue: () => App<Element>) {
|
|||||||
}, { immediate: true });
|
}, { immediate: true });
|
||||||
|
|
||||||
watch(prefer.r.useBlurEffectForModal, v => {
|
watch(prefer.r.useBlurEffectForModal, v => {
|
||||||
window.document.documentElement.style.setProperty('--MI-modalBgFilter', v ? 'blur(4px)' : 'none');
|
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) {
|
||||||
window.document.documentElement.style.removeProperty('--MI-blur');
|
document.documentElement.style.removeProperty('--MI-blur');
|
||||||
} else {
|
} else {
|
||||||
window.document.documentElement.style.setProperty('--MI-blur', 'none');
|
document.documentElement.style.setProperty('--MI-blur', 'none');
|
||||||
}
|
}
|
||||||
}, { immediate: true });
|
}, { immediate: true });
|
||||||
|
|
||||||
// Keep screen on
|
// Keep screen on
|
||||||
const onVisibilityChange = () => window.document.addEventListener('visibilitychange', () => {
|
const onVisibilityChange = () => document.addEventListener('visibilitychange', () => {
|
||||||
if (window.document.visibilityState === 'visible') {
|
if (document.visibilityState === 'visible') {
|
||||||
navigator.wakeLock.request('screen');
|
navigator.wakeLock.request('screen');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -208,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/
|
||||||
window.document.addEventListener(
|
document.addEventListener(
|
||||||
'click',
|
'click',
|
||||||
() => navigator.wakeLock.request('screen').then(onVisibilityChange),
|
() => navigator.wakeLock.request('screen').then(onVisibilityChange),
|
||||||
{ once: true },
|
{ once: true },
|
||||||
@@ -217,7 +233,7 @@ export async function common(createVue: () => App<Element>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (prefer.s.makeEveryTextElementsSelectable) {
|
if (prefer.s.makeEveryTextElementsSelectable) {
|
||||||
window.document.documentElement.classList.add('forceSelectableAll');
|
document.documentElement.classList.add('forceSelectableAll');
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region Fetch user
|
//#region Fetch user
|
||||||
@@ -262,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 = window.document.getElementById(MISSKEY_MOUNT_DIV_ID);
|
const currentRoot = 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 = window.document.createElement('div');
|
const root = document.createElement('div');
|
||||||
root.id = MISSKEY_MOUNT_DIV_ID;
|
root.id = MISSKEY_MOUNT_DIV_ID;
|
||||||
window.document.body.appendChild(root);
|
document.body.appendChild(root);
|
||||||
return root;
|
return root;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
@@ -314,7 +330,7 @@ export async function common(createVue: () => App<Element>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function removeSplash() {
|
function removeSplash() {
|
||||||
const splash = window.document.getElementById('splash');
|
const splash = 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'] && window.location.pathname !== '/') uiStyle = 'zen';
|
if (uiStyle === 'deck' && prefer.s['deck.useSimpleUiForNonRootPages'] && 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') {
|
||||||
window.location.reload();
|
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) {
|
||||||
window.location.reload();
|
location.reload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -398,7 +398,7 @@ export async function mainBoot() {
|
|||||||
let lastVisibilityChangedAt = Date.now();
|
let lastVisibilityChangedAt = Date.now();
|
||||||
|
|
||||||
function claimPlainLucky() {
|
function claimPlainLucky() {
|
||||||
if (window.document.visibilityState !== 'visible') {
|
if (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 (window.document.visibilityState === 'visible') {
|
if (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))) && !window.location.pathname.startsWith('/miauth')) {
|
if (neverShowDonationInfo !== 'true' && (createdAt.getTime() < (Date.now() - (1000 * 60 * 60 * 24 * 3))) && !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;
|
||||||
window.document.addEventListener('keydown', makeHotkey(keymap), { passive: false });
|
document.addEventListener('keydown', makeHotkey(keymap), { passive: false });
|
||||||
|
|
||||||
initializeSw();
|
initializeSw();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ function tick() {
|
|||||||
tick();
|
tick();
|
||||||
|
|
||||||
function calcColors() {
|
function calcColors() {
|
||||||
const computedStyle = getComputedStyle(window.document.documentElement);
|
const computedStyle = getComputedStyle(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);
|
||||||
|
|
||||||
window.document.body.addEventListener('mousedown', onMousedown);
|
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);
|
||||||
|
|
||||||
window.document.body.removeEventListener('mousedown', onMousedown);
|
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 = window.document.createElement('div');
|
const ripple = 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) {
|
||||||
(window.document.getElementById(scriptId.value) ?? window.document.head.appendChild(Object.assign(window.document.createElement('script'), {
|
(document.getElementById(scriptId.value) ?? document.head.appendChild(Object.assign(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 = window.document.createElement('div');
|
const elem = 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 = window.document.getElementById('mcaptcha__widget-container');
|
const container = 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`;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.document.body.addEventListener('mousedown', onMousedown);
|
document.body.addEventListener('mousedown', onMousedown);
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
window.document.body.removeEventListener('mousedown', onMousedown);
|
document.body.removeEventListener('mousedown', onMousedown);
|
||||||
});
|
});
|
||||||
|
|
||||||
function onMousedown(evt: Event) {
|
function onMousedown(evt: Event) {
|
||||||
|
|||||||
@@ -3,12 +3,14 @@
|
|||||||
* 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 {
|
||||||
@@ -53,7 +55,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 window.fetch('client-assets/fedi.jpg')).blob();
|
const image = await (await 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(window.document.documentElement);
|
const computedStyle = getComputedStyle(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?.window.location.reload();
|
iframeEl.value?.contentWindow?.location.reload();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ function toggle() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const computedStyle = getComputedStyle(window.document.documentElement);
|
const computedStyle = getComputedStyle(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;
|
||||||
|
|||||||
@@ -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 = window.document.createElement('canvas');
|
const canvas = 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 = window.document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
canvas.width = 64;
|
canvas.width = 64;
|
||||||
canvas.height = 64;
|
canvas.height = 64;
|
||||||
resolve(canvas);
|
resolve(canvas);
|
||||||
|
|||||||
@@ -3,12 +3,13 @@
|
|||||||
* 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) {
|
||||||
@@ -47,7 +48,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 window.fetch(`client-assets/${url.pathname.split('/').pop()}`)).blob();
|
const image = await (await 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(window.document.documentElement).getPropertyValue('--MI_THEME-panel'),
|
borderColor: getComputedStyle(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 === window.document.activeElement || playerEl.value.contains(window.document.activeElement);
|
return playerEl.value === document.activeElement || playerEl.value.contains(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');
|
||||||
window.document.documentElement.style.setProperty('--mk-pswp-root-z-index', pswpZIndex.toString());
|
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 = window.document.createElement('p');
|
const textBox = 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 = window.document.activeElement instanceof HTMLElement ? window.document.activeElement : null;
|
activeEl = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
||||||
focusParent(activeEl, true, true);
|
focusParent(activeEl, true, true);
|
||||||
lightbox?.pswp?.element?.focus({
|
lightbox?.pswp?.element?.focus({
|
||||||
preventScroll: true,
|
preventScroll: true,
|
||||||
});
|
});
|
||||||
window.history.pushState(null, '', '#pswp');
|
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') {
|
||||||
window.history.back();
|
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 === window.document.activeElement || playerEl.value.contains(window.document.activeElement);
|
return playerEl.value === document.activeElement || playerEl.value.contains(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,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
...(window.document.pictureInPictureEnabled ? [{
|
...(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 (window.document.pictureInPictureElement) {
|
if (document.pictureInPictureElement) {
|
||||||
window.document.exitPictureInPicture();
|
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(window.document.activeElement)) return;
|
if (!itemsEl.value?.contains(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 === window.document.activeElement);
|
const activeIndex = focusableElements.findIndex(el => el === 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(window.document.activeElement)) return;
|
if (!itemsEl.value?.contains(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 === window.document.activeElement);
|
const activeIndex = focusableElements.findIndex(el => el === 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) {
|
||||||
window.document.addEventListener('focusin', onGlobalFocusin, { passive: true });
|
document.addEventListener('focusin', onGlobalFocusin, { passive: true });
|
||||||
}
|
}
|
||||||
window.document.addEventListener('mousedown', onGlobalMousedown, { passive: true });
|
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) {
|
||||||
window.document.removeEventListener('focusin', onGlobalFocusin);
|
document.removeEventListener('focusin', onGlobalFocusin);
|
||||||
}
|
}
|
||||||
window.document.removeEventListener('mousedown', onGlobalMousedown);
|
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(window.document.documentElement).getPropertyValue('--MI_THEME-accent'));
|
const accent = tinycolor(getComputedStyle(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 || window.document.visibilityState === 'visible') {
|
if (isMuted || 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) : window.document.body);
|
const scrollableElement = computed(() => contentEl.value ? getScrollContainer(contentEl.value) : document.body);
|
||||||
|
|
||||||
const visibility = useDocumentVisibility();
|
const visibility = useDocumentVisibility();
|
||||||
|
|
||||||
|
|||||||
@@ -151,9 +151,9 @@ function onMousedown(ev: MouseEvent | TouchEvent) {
|
|||||||
closed: () => dispose(),
|
closed: () => dispose(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const style = window.document.createElement('style');
|
const style = document.createElement('style');
|
||||||
style.appendChild(window.document.createTextNode('* { cursor: grabbing !important; } body * { pointer-events: none !important; }'));
|
style.appendChild(document.createTextNode('* { cursor: grabbing !important; } body * { pointer-events: none !important; }'));
|
||||||
window.document.head.appendChild(style);
|
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 = () => {
|
||||||
window.document.head.removeChild(style);
|
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 (window.document.hidden || !prefer.s.animation || buttonEl.value == null) return;
|
if (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(window.document.documentElement).getPropertyValue('--MI_THEME-accent'));
|
const accent = tinycolor(getComputedStyle(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="emit('closed')"
|
@closed="console.log('MkRoleSelectDialog: closed') ; $emit('dispose')"
|
||||||
>
|
>
|
||||||
<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: 'closed'),
|
(ev: 'dispose'),
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
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 window.fetch(`${config.apiUrl}/signup`, {
|
const res = await 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(window.document.documentElement);
|
const computedStyle = getComputedStyle(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 {
|
||||||
window.document.head.appendChild(Object.assign(window.document.createElement('script'), {
|
document.head.appendChild(Object.assign(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(window.document.documentElement);
|
const computedStyle = getComputedStyle(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, window.document.activeElement)) main.focus();
|
if (!contains(main, 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') {
|
||||||
window.location.href = props.to;
|
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 (window.document.body.contains(el.value as HTMLElement)) {
|
if (document.body.contains(el.value as HTMLElement)) {
|
||||||
nextTick(() => renderTab());
|
nextTick(() => renderTab());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -69,8 +69,6 @@ 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);
|
||||||
|
|
||||||
@@ -108,7 +106,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(window.document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg);
|
const tinyBg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg);
|
||||||
tinyBg.setAlpha(0.85);
|
tinyBg.setAlpha(0.85);
|
||||||
bg.value = tinyBg.toRgbString();
|
bg.value = tinyBg.toRgbString();
|
||||||
};
|
};
|
||||||
@@ -122,7 +120,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 && window.document.body.contains(el.value as HTMLElement)) {
|
if (el.value && el.value.parentElement && document.body.contains(el.value as HTMLElement)) {
|
||||||
narrow.value = el.value.parentElement.offsetWidth < 500;
|
narrow.value = el.value.parentElement.offsetWidth < 500;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -142,7 +140,6 @@ 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,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div ref="rootEl" class="_pageContainer" :class="$style.root">
|
<div class="_pageContainer" style="height: 100%;">
|
||||||
<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,13 +18,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { inject, nextTick, onMounted, provide, ref, shallowRef, useTemplateRef } from 'vue';
|
import { inject, provide, ref, shallowRef } 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;
|
||||||
@@ -36,76 +34,18 @@ 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;
|
||||||
if (resolved.route.path === currentRoutePath && deepEqual(resolved.props, currentPageProps.value)) return;
|
|
||||||
|
|
||||||
function _() {
|
|
||||||
currentPageComponent.value = resolved.route.component;
|
currentPageComponent.value = resolved.route.component;
|
||||||
currentPageProps.value = resolved.props;
|
currentPageProps.value = resolved.props;
|
||||||
key.value = router.getCurrentFullPath();
|
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 = window.document.querySelector(`[data-in-app-search-marker-id="${searchMarkerId.value}"]`);
|
const el = document.querySelector(`[data-in-app-search-marker-id="${searchMarkerId.value}"]`);
|
||||||
highlighted.value = el == null;
|
highlighted.value = el == null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,5 +11,4 @@ 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>,
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export default {
|
|||||||
el._keyHandler = makeHotkey(binding.value);
|
el._keyHandler = makeHotkey(binding.value);
|
||||||
|
|
||||||
if (el._hotkey_global) {
|
if (el._hotkey_global) {
|
||||||
window.document.addEventListener('keydown', el._keyHandler, { passive: false });
|
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) {
|
||||||
window.document.removeEventListener('keydown', el._keyHandler);
|
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(window.document.documentElement).getPropertyValue('--MI_THEME-panel');
|
const myBg = getComputedStyle(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 (!window.document.body.contains(el)) return;
|
if (!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 (!window.document.body.contains(this.el)) return;
|
if (!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 (!window.document.body.contains(this.el)) {
|
if (!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 = window.document.getElementById('misskey_meta');
|
const providedMetaEl = 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 === '/:(*)') {
|
||||||
window.location.href = fullPath;
|
location.href = fullPath;
|
||||||
} else {
|
} else {
|
||||||
this.emit('push', {
|
this.emit('push', {
|
||||||
beforeFullPath,
|
beforeFullPath,
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ export type Keys = (
|
|||||||
'fontSize' |
|
'fontSize' |
|
||||||
'ui' |
|
'ui' |
|
||||||
'ui_temp' |
|
'ui_temp' |
|
||||||
'locale' | // DEPRECATED
|
'locale' |
|
||||||
'localeVersion' | // DEPRECATED
|
'localeVersion' |
|
||||||
'theme' |
|
'theme' |
|
||||||
'themeId' |
|
'themeId' |
|
||||||
'customCss' |
|
'customCss' |
|
||||||
|
|||||||
@@ -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) => {
|
||||||
window.location.reload();
|
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: Partial<ComponentEmit<T>> = {},
|
events: ComponentEmit<T> = {} as 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(defineAsyncComponent(() => import('@/components/MkPasswordDialog.vue')), {}, {
|
const { dispose } = popup(MkPasswordDialog, {}, {
|
||||||
done: result => {
|
done: result => {
|
||||||
resolve(result ? { canceled: false, result } : { canceled: true, result: undefined });
|
resolve(result ? { canceled: false, result } : { canceled: true, result: undefined });
|
||||||
},
|
},
|
||||||
@@ -617,26 +617,30 @@ export async function selectDriveFolder(multiple: boolean): Promise<Misskey.enti
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function selectRole(params: ComponentProps<typeof MkRoleSelectDialog_TypeReferenceOnly>): Promise<
|
export async function selectRole(params: {
|
||||||
|
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) => {
|
||||||
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkRoleSelectDialog.vue')), params, {
|
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 });
|
||||||
},
|
},
|
||||||
closed: () => dispose(),
|
}, 'dispose');
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function pickEmoji(src: HTMLElement, opts: ComponentProps<typeof MkEmojiPickerDialog_TypeReferenceOnly>): Promise<string> {
|
export async function pickEmoji(src: HTMLElement, opts: ComponentProps<typeof MkEmojiPickerDialog>): Promise<string> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkEmojiPickerDialog.vue')), {
|
const { dispose } = popup(MkEmojiPickerDialog, {
|
||||||
src,
|
src,
|
||||||
...opts,
|
...opts,
|
||||||
}, {
|
}, {
|
||||||
@@ -671,11 +675,7 @@ export function popupMenu(items: MenuItem[], src?: HTMLElement | EventTarget | n
|
|||||||
width?: number;
|
width?: number;
|
||||||
onClosing?: () => void;
|
onClosing?: () => void;
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
if (!(src instanceof HTMLElement)) {
|
let returnFocusTo = getHTMLElementOrNull(src) ?? getHTMLElementOrNull(document.activeElement);
|
||||||
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(window.document.activeElement);
|
let returnFocusTo = getHTMLElementOrNull(ev.currentTarget ?? ev.target) ?? getHTMLElementOrNull(document.activeElement);
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
return new Promise(resolve => nextTick(() => {
|
return new Promise(resolve => nextTick(() => {
|
||||||
const { dispose } = popup(MkContextMenu, {
|
const { dispose } = popup(MkContextMenu, {
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ function onTabClick(tab: Tab, ev: MouseEvent): void {
|
|||||||
|
|
||||||
const calcBg = () => {
|
const calcBg = () => {
|
||||||
const rawBg = pageMetadata.value.bg ?? 'var(--MI_THEME-bg)';
|
const rawBg = pageMetadata.value.bg ?? 'var(--MI_THEME-bg)';
|
||||||
const tinyBg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(window.document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg);
|
const tinyBg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg);
|
||||||
tinyBg.setAlpha(0.85);
|
tinyBg.setAlpha(0.85);
|
||||||
bg.value = tinyBg.toRgbString();
|
bg.value = tinyBg.toRgbString();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ onMounted(() => {
|
|||||||
labels: props.data.map(x => x.name),
|
labels: props.data.map(x => x.name),
|
||||||
datasets: [{
|
datasets: [{
|
||||||
backgroundColor: props.data.map(x => x.color),
|
backgroundColor: props.data.map(x => x.color),
|
||||||
borderColor: getComputedStyle(window.document.documentElement).getPropertyValue('--MI_THEME-panel'),
|
borderColor: getComputedStyle(document.documentElement).getPropertyValue('--MI_THEME-panel'),
|
||||||
borderWidth: 2,
|
borderWidth: 2,
|
||||||
hoverOffset: 0,
|
hoverOffset: 0,
|
||||||
data: props.data.map(x => x.value),
|
data: props.data.map(x => x.value),
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ const emit = defineEmits<{
|
|||||||
const app = computed(() => props.session.app);
|
const app = computed(() => props.session.app);
|
||||||
|
|
||||||
const name = computed(() => {
|
const name = computed(() => {
|
||||||
const el = window.document.createElement('div');
|
const el = document.createElement('div');
|
||||||
el.textContent = app.value.name;
|
el.textContent = app.value.name;
|
||||||
return el.innerHTML;
|
return el.innerHTML;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ function accepted() {
|
|||||||
if (session.value && session.value.app.callbackUrl) {
|
if (session.value && session.value.app.callbackUrl) {
|
||||||
const url = new URL(session.value.app.callbackUrl);
|
const url = new URL(session.value.app.callbackUrl);
|
||||||
if (['javascript:', 'file:', 'data:', 'mailto:', 'tel:', 'vbscript:'].includes(url.protocol)) throw new Error('invalid url');
|
if (['javascript:', 'file:', 'data:', 'mailto:', 'tel:', 'vbscript:'].includes(url.protocol)) throw new Error('invalid url');
|
||||||
window.location.href = `${session.value.app.callbackUrl}?token=${session.value.token}`;
|
location.href = `${session.value.app.callbackUrl}?token=${session.value.token}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -632,7 +632,7 @@ function loadMonoTextures() {
|
|||||||
src = URL.createObjectURL(monoTextures[mono.img]);
|
src = URL.createObjectURL(monoTextures[mono.img]);
|
||||||
monoTextureUrls[mono.img] = src;
|
monoTextureUrls[mono.img] = src;
|
||||||
} else {
|
} else {
|
||||||
const res = await window.fetch(mono.img);
|
const res = await fetch(mono.img);
|
||||||
const blob = await res.blob();
|
const blob = await res.blob();
|
||||||
monoTextures[mono.img] = blob;
|
monoTextures[mono.img] = blob;
|
||||||
src = URL.createObjectURL(blob);
|
src = URL.createObjectURL(blob);
|
||||||
@@ -875,7 +875,7 @@ function loadImage(url: string) {
|
|||||||
|
|
||||||
function getGameImageDriveFile() {
|
function getGameImageDriveFile() {
|
||||||
return new Promise<Misskey.entities.DriveFile | null>(res => {
|
return new Promise<Misskey.entities.DriveFile | null>(res => {
|
||||||
const dcanvas = window.document.createElement('canvas');
|
const dcanvas = document.createElement('canvas');
|
||||||
dcanvas.width = game.GAME_WIDTH;
|
dcanvas.width = game.GAME_WIDTH;
|
||||||
dcanvas.height = game.GAME_HEIGHT;
|
dcanvas.height = game.GAME_HEIGHT;
|
||||||
const ctx = dcanvas.getContext('2d');
|
const ctx = dcanvas.getContext('2d');
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import MkButton from '@/components/MkButton.vue';
|
|||||||
const state = ref<'fetching' | 'done'>('fetching');
|
const state = ref<'fetching' | 'done'>('fetching');
|
||||||
|
|
||||||
function fetch() {
|
function fetch() {
|
||||||
const params = new URL(window.location.href).searchParams;
|
const params = new URL(location.href).searchParams;
|
||||||
|
|
||||||
// acctのほうはdeprecated
|
// acctのほうはdeprecated
|
||||||
let uri = params.get('uri') ?? params.get('acct');
|
let uri = params.get('uri') ?? params.get('acct');
|
||||||
@@ -76,12 +76,12 @@ function close(): void {
|
|||||||
|
|
||||||
// 閉じなければ100ms後タイムラインに
|
// 閉じなければ100ms後タイムラインに
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
window.location.href = '/';
|
location.href = '/';
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
function goToMisskey(): void {
|
function goToMisskey(): void {
|
||||||
window.location.href = '/';
|
location.href = '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch();
|
fetch();
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ async function onAccept(token: string) {
|
|||||||
const cbUrl = new URL(props.callback);
|
const cbUrl = new URL(props.callback);
|
||||||
if (['javascript:', 'file:', 'data:', 'mailto:', 'tel:', 'vbscript:'].includes(cbUrl.protocol)) throw new Error('invalid url');
|
if (['javascript:', 'file:', 'data:', 'mailto:', 'tel:', 'vbscript:'].includes(cbUrl.protocol)) throw new Error('invalid url');
|
||||||
cbUrl.searchParams.set('session', props.session);
|
cbUrl.searchParams.set('session', props.session);
|
||||||
window.location.href = cbUrl.toString();
|
location.href = cbUrl.toString();
|
||||||
} else {
|
} else {
|
||||||
authRoot.value?.showUI('success');
|
authRoot.value?.showUI('success');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,42 +27,42 @@ import MkPageWithAnimBg from '@/components/MkPageWithAnimBg.vue';
|
|||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import MkAuthConfirm from '@/components/MkAuthConfirm.vue';
|
import MkAuthConfirm from '@/components/MkAuthConfirm.vue';
|
||||||
|
|
||||||
const transactionIdMeta = window.document.querySelector<HTMLMetaElement>('meta[name="misskey:oauth:transaction-id"]');
|
const transactionIdMeta = document.querySelector<HTMLMetaElement>('meta[name="misskey:oauth:transaction-id"]');
|
||||||
if (transactionIdMeta) {
|
if (transactionIdMeta) {
|
||||||
transactionIdMeta.remove();
|
transactionIdMeta.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
const name = window.document.querySelector<HTMLMetaElement>('meta[name="misskey:oauth:client-name"]')?.content;
|
const name = document.querySelector<HTMLMetaElement>('meta[name="misskey:oauth:client-name"]')?.content;
|
||||||
const logo = window.document.querySelector<HTMLMetaElement>('meta[name="misskey:oauth:client-logo"]')?.content;
|
const logo = document.querySelector<HTMLMetaElement>('meta[name="misskey:oauth:client-logo"]')?.content;
|
||||||
const permissions = window.document.querySelector<HTMLMetaElement>('meta[name="misskey:oauth:scope"]')?.content.split(' ').filter((p): p is typeof Misskey.permissions[number] => (Misskey.permissions as readonly string[]).includes(p)) ?? [];
|
const permissions = document.querySelector<HTMLMetaElement>('meta[name="misskey:oauth:scope"]')?.content.split(' ').filter((p): p is typeof Misskey.permissions[number] => (Misskey.permissions as readonly string[]).includes(p)) ?? [];
|
||||||
|
|
||||||
function doPost(token: string, decision: 'accept' | 'deny') {
|
function doPost(token: string, decision: 'accept' | 'deny') {
|
||||||
const form = window.document.createElement('form');
|
const form = document.createElement('form');
|
||||||
form.action = '/oauth/decision';
|
form.action = '/oauth/decision';
|
||||||
form.method = 'post';
|
form.method = 'post';
|
||||||
form.acceptCharset = 'utf-8';
|
form.acceptCharset = 'utf-8';
|
||||||
|
|
||||||
const loginToken = window.document.createElement('input');
|
const loginToken = document.createElement('input');
|
||||||
loginToken.type = 'hidden';
|
loginToken.type = 'hidden';
|
||||||
loginToken.name = 'login_token';
|
loginToken.name = 'login_token';
|
||||||
loginToken.value = token;
|
loginToken.value = token;
|
||||||
form.appendChild(loginToken);
|
form.appendChild(loginToken);
|
||||||
|
|
||||||
const transactionId = window.document.createElement('input');
|
const transactionId = document.createElement('input');
|
||||||
transactionId.type = 'hidden';
|
transactionId.type = 'hidden';
|
||||||
transactionId.name = 'transaction_id';
|
transactionId.name = 'transaction_id';
|
||||||
transactionId.value = transactionIdMeta?.content ?? '';
|
transactionId.value = transactionIdMeta?.content ?? '';
|
||||||
form.appendChild(transactionId);
|
form.appendChild(transactionId);
|
||||||
|
|
||||||
if (decision === 'deny') {
|
if (decision === 'deny') {
|
||||||
const cancel = window.document.createElement('input');
|
const cancel = document.createElement('input');
|
||||||
cancel.type = 'hidden';
|
cancel.type = 'hidden';
|
||||||
cancel.name = 'cancel';
|
cancel.name = 'cancel';
|
||||||
cancel.value = 'cancel';
|
cancel.value = 'cancel';
|
||||||
form.appendChild(cancel);
|
form.appendChild(cancel);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.document.body.appendChild(form);
|
document.body.appendChild(form);
|
||||||
form.submit();
|
form.submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ async function tokenDone() {
|
|||||||
function downloadBackupCodes() {
|
function downloadBackupCodes() {
|
||||||
if (backupCodes.value !== undefined) {
|
if (backupCodes.value !== undefined) {
|
||||||
const txtBlob = new Blob([backupCodes.value.join('\n')], { type: 'text/plain' });
|
const txtBlob = new Blob([backupCodes.value.join('\n')], { type: 'text/plain' });
|
||||||
const dummya = window.document.createElement('a');
|
const dummya = document.createElement('a');
|
||||||
dummya.href = URL.createObjectURL(txtBlob);
|
dummya.href = URL.createObjectURL(txtBlob);
|
||||||
dummya.download = `${$i.username}@${hostname}` + (port !== '' ? `_${port}` : '') + '-2fa-backup-codes.txt';
|
dummya.download = `${$i.username}@${hostname}` + (port !== '' ? `_${port}` : '') + '-2fa-backup-codes.txt';
|
||||||
dummya.click();
|
dummya.click();
|
||||||
|
|||||||
@@ -606,6 +606,8 @@ const defaultFollowWithReplies = prefer.model('defaultFollowWithReplies');
|
|||||||
|
|
||||||
watch(lang, () => {
|
watch(lang, () => {
|
||||||
miLocalStorage.setItem('lang', lang.value as string);
|
miLocalStorage.setItem('lang', lang.value as string);
|
||||||
|
miLocalStorage.removeItem('locale');
|
||||||
|
miLocalStorage.removeItem('localeVersion');
|
||||||
});
|
});
|
||||||
|
|
||||||
watch([
|
watch([
|
||||||
|
|||||||
@@ -182,12 +182,12 @@ function close(): void {
|
|||||||
|
|
||||||
// 閉じなければ100ms後タイムラインに
|
// 閉じなければ100ms後タイムラインに
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
window.location.href = '/';
|
location.href = '/';
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
function goToMisskey(): void {
|
function goToMisskey(): void {
|
||||||
window.location.href = '/';
|
location.href = '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
function onPosted(): void {
|
function onPosted(): void {
|
||||||
|
|||||||
@@ -125,8 +125,8 @@ function syncBetweenTabs() {
|
|||||||
|
|
||||||
window.setInterval(syncBetweenTabs, 5000);
|
window.setInterval(syncBetweenTabs, 5000);
|
||||||
|
|
||||||
window.document.addEventListener('visibilitychange', () => {
|
document.addEventListener('visibilitychange', () => {
|
||||||
if (window.document.visibilityState === 'visible') {
|
if (document.visibilityState === 'visible') {
|
||||||
syncBetweenTabs();
|
syncBetweenTabs();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -136,7 +136,7 @@ let latestBackupAt = 0;
|
|||||||
window.setInterval(() => {
|
window.setInterval(() => {
|
||||||
if ($i == null) return;
|
if ($i == null) return;
|
||||||
if (!store.s.enablePreferencesAutoCloudBackup) return;
|
if (!store.s.enablePreferencesAutoCloudBackup) return;
|
||||||
if (window.document.visibilityState !== 'visible') return; // 同期されていない古い値がバックアップされるのを防ぐ
|
if (document.visibilityState !== 'visible') return; // 同期されていない古い値がバックアップされるのを防ぐ
|
||||||
if (prefer.profile.modifiedAt <= latestBackupAt) return;
|
if (prefer.profile.modifiedAt <= latestBackupAt) return;
|
||||||
|
|
||||||
cloudBackup().then(() => {
|
cloudBackup().then(() => {
|
||||||
|
|||||||
@@ -106,14 +106,14 @@ async function renameProfile() {
|
|||||||
function exportCurrentProfile() {
|
function exportCurrentProfile() {
|
||||||
const p = prefer.profile;
|
const p = prefer.profile;
|
||||||
const txtBlob = new Blob([JSON.stringify(p)], { type: 'text/plain' });
|
const txtBlob = new Blob([JSON.stringify(p)], { type: 'text/plain' });
|
||||||
const dummya = window.document.createElement('a');
|
const dummya = document.createElement('a');
|
||||||
dummya.href = URL.createObjectURL(txtBlob);
|
dummya.href = URL.createObjectURL(txtBlob);
|
||||||
dummya.download = `${p.name || p.id}.misskeypreferences`;
|
dummya.download = `${p.name || p.id}.misskeypreferences`;
|
||||||
dummya.click();
|
dummya.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
function importProfile() {
|
function importProfile() {
|
||||||
const input = window.document.createElement('input');
|
const input = document.createElement('input');
|
||||||
input.type = 'file';
|
input.type = 'file';
|
||||||
input.accept = '.misskeypreferences';
|
input.accept = '.misskeypreferences';
|
||||||
input.onchange = async () => {
|
input.onchange = async () => {
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ export function createRouter(fullPath: string): Router {
|
|||||||
return new Nirax(ROUTE_DEF, fullPath, !!$i, page(() => import('@/pages/not-found.vue')));
|
return new Nirax(ROUTE_DEF, fullPath, !!$i, page(() => import('@/pages/not-found.vue')));
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mainRouter = createRouter(window.location.pathname + window.location.search + window.location.hash);
|
export const mainRouter = createRouter(location.pathname + location.search + location.hash);
|
||||||
|
|
||||||
window.addEventListener('popstate', (event) => {
|
window.addEventListener('popstate', (event) => {
|
||||||
mainRouter.replace(window.location.pathname + window.location.search + window.location.hash);
|
mainRouter.replace(location.pathname + location.search + location.hash);
|
||||||
});
|
});
|
||||||
|
|
||||||
mainRouter.addListener('push', ctx => {
|
mainRouter.addListener('push', ctx => {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
|
|
||||||
const providedContextEl = window.document.getElementById('misskey_clientCtx');
|
const providedContextEl = document.getElementById('misskey_clientCtx');
|
||||||
|
|
||||||
export type ServerContext = {
|
export type ServerContext = {
|
||||||
clip?: Misskey.entities.Clip;
|
clip?: Misskey.entities.Clip;
|
||||||
|
|||||||
@@ -29,10 +29,10 @@ export function useStream(): Misskey.IStream {
|
|||||||
timeoutHeartBeat = window.setTimeout(heartbeat, HEART_BEAT_INTERVAL);
|
timeoutHeartBeat = window.setTimeout(heartbeat, HEART_BEAT_INTERVAL);
|
||||||
|
|
||||||
// send heartbeat right now when last send time is over HEART_BEAT_INTERVAL
|
// send heartbeat right now when last send time is over HEART_BEAT_INTERVAL
|
||||||
window.document.addEventListener('visibilitychange', () => {
|
document.addEventListener('visibilitychange', () => {
|
||||||
if (
|
if (
|
||||||
!stream
|
!stream
|
||||||
|| window.document.visibilityState !== 'visible'
|
|| document.visibilityState !== 'visible'
|
||||||
|| Date.now() - lastHeartbeatCall < HEART_BEAT_INTERVAL
|
|| Date.now() - lastHeartbeatCall < HEART_BEAT_INTERVAL
|
||||||
) return;
|
) return;
|
||||||
heartbeat();
|
heartbeat();
|
||||||
@@ -42,7 +42,7 @@ export function useStream(): Misskey.IStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function heartbeat(): void {
|
function heartbeat(): void {
|
||||||
if (stream != null && window.document.visibilityState === 'visible') {
|
if (stream != null && document.visibilityState === 'visible') {
|
||||||
stream.heartbeat();
|
stream.heartbeat();
|
||||||
}
|
}
|
||||||
lastHeartbeatCall = Date.now();
|
lastHeartbeatCall = Date.now();
|
||||||
|
|||||||
@@ -68,10 +68,10 @@ let timeout: number | null = null;
|
|||||||
export function applyTheme(theme: Theme, persist = true) {
|
export function applyTheme(theme: Theme, persist = true) {
|
||||||
if (timeout) window.clearTimeout(timeout);
|
if (timeout) window.clearTimeout(timeout);
|
||||||
|
|
||||||
window.document.documentElement.classList.add('_themeChanging_');
|
document.documentElement.classList.add('_themeChanging_');
|
||||||
|
|
||||||
timeout = window.setTimeout(() => {
|
timeout = window.setTimeout(() => {
|
||||||
window.document.documentElement.classList.remove('_themeChanging_');
|
document.documentElement.classList.remove('_themeChanging_');
|
||||||
|
|
||||||
// 色計算など再度行えるようにクライアント全体に通知
|
// 色計算など再度行えるようにクライアント全体に通知
|
||||||
globalEvents.emit('themeChanged');
|
globalEvents.emit('themeChanged');
|
||||||
@@ -79,7 +79,7 @@ export function applyTheme(theme: Theme, persist = true) {
|
|||||||
|
|
||||||
const colorScheme = theme.base === 'dark' ? 'dark' : 'light';
|
const colorScheme = theme.base === 'dark' ? 'dark' : 'light';
|
||||||
|
|
||||||
window.document.documentElement.dataset.colorScheme = colorScheme;
|
document.documentElement.dataset.colorScheme = colorScheme;
|
||||||
|
|
||||||
// Deep copy
|
// Deep copy
|
||||||
const _theme = deepClone(theme);
|
const _theme = deepClone(theme);
|
||||||
@@ -91,7 +91,7 @@ export function applyTheme(theme: Theme, persist = true) {
|
|||||||
|
|
||||||
const props = compile(_theme);
|
const props = compile(_theme);
|
||||||
|
|
||||||
for (const tag of window.document.head.children) {
|
for (const tag of document.head.children) {
|
||||||
if (tag.tagName === 'META' && tag.getAttribute('name') === 'theme-color') {
|
if (tag.tagName === 'META' && tag.getAttribute('name') === 'theme-color') {
|
||||||
tag.setAttribute('content', props['htmlThemeColor']);
|
tag.setAttribute('content', props['htmlThemeColor']);
|
||||||
break;
|
break;
|
||||||
@@ -99,10 +99,10 @@ export function applyTheme(theme: Theme, persist = true) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const [k, v] of Object.entries(props)) {
|
for (const [k, v] of Object.entries(props)) {
|
||||||
window.document.documentElement.style.setProperty(`--MI_THEME-${k}`, v.toString());
|
document.documentElement.style.setProperty(`--MI_THEME-${k}`, v.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
window.document.documentElement.style.setProperty('color-scheme', colorScheme);
|
document.documentElement.style.setProperty('color-scheme', colorScheme);
|
||||||
|
|
||||||
if (persist) {
|
if (persist) {
|
||||||
miLocalStorage.setItem('theme', JSON.stringify(props));
|
miLocalStorage.setItem('theme', JSON.stringify(props));
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ const dev = _DEV_;
|
|||||||
const notifications = ref<Misskey.entities.Notification[]>([]);
|
const notifications = ref<Misskey.entities.Notification[]>([]);
|
||||||
|
|
||||||
function onNotification(notification: Misskey.entities.Notification, isClient = false) {
|
function onNotification(notification: Misskey.entities.Notification, isClient = false) {
|
||||||
if (window.document.visibilityState === 'visible') {
|
if (document.visibilityState === 'visible') {
|
||||||
if (!isClient && notification.type !== 'test') {
|
if (!isClient && notification.type !== 'test') {
|
||||||
// サーバーサイドのテスト通知の際は自動で既読をつけない(テストできないので)
|
// サーバーサイドのテスト通知の際は自動で既読をつけない(テストできないので)
|
||||||
useStream().send('readNotification');
|
useStream().send('readNotification');
|
||||||
|
|||||||
@@ -129,8 +129,8 @@ watch(store.r.menuDisplay, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function toggleIconOnly() {
|
function toggleIconOnly() {
|
||||||
if (window.document.startViewTransition && prefer.s.animation) {
|
if (document.startViewTransition && prefer.s.animation) {
|
||||||
window.document.startViewTransition(() => {
|
document.startViewTransition(() => {
|
||||||
store.set('menuDisplay', iconOnly.value ? 'sideFull' : 'sideIcon');
|
store.set('menuDisplay', iconOnly.value ? 'sideFull' : 'sideIcon');
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ function resetDisconnected() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function reload() {
|
function reload() {
|
||||||
window.location.reload();
|
location.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
useStream().on('_disconnected_', onDisconnected);
|
useStream().on('_disconnected_', onDisconnected);
|
||||||
|
|||||||
@@ -87,9 +87,9 @@ provideMetadataReceiver((metadataGetter) => {
|
|||||||
pageMetadata.value = info;
|
pageMetadata.value = info;
|
||||||
if (pageMetadata.value) {
|
if (pageMetadata.value) {
|
||||||
if (isRoot.value && pageMetadata.value.title === instanceName) {
|
if (isRoot.value && pageMetadata.value.title === instanceName) {
|
||||||
window.document.title = pageMetadata.value.title;
|
document.title = pageMetadata.value.title;
|
||||||
} else {
|
} else {
|
||||||
window.document.title = `${pageMetadata.value.title} | ${instanceName}`;
|
document.title = `${pageMetadata.value.title} | ${instanceName}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -139,10 +139,10 @@ if (window.innerWidth < 1024) {
|
|||||||
const currentUI = miLocalStorage.getItem('ui');
|
const currentUI = miLocalStorage.getItem('ui');
|
||||||
miLocalStorage.setItem('ui_temp', currentUI ?? 'default');
|
miLocalStorage.setItem('ui_temp', currentUI ?? 'default');
|
||||||
miLocalStorage.setItem('ui', 'default');
|
miLocalStorage.setItem('ui', 'default');
|
||||||
window.location.reload();
|
location.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
window.document.documentElement.style.overflowY = 'scroll';
|
document.documentElement.style.overflowY = 'scroll';
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
window.addEventListener('resize', () => {
|
window.addEventListener('resize', () => {
|
||||||
|
|||||||
@@ -202,8 +202,8 @@ function onWheel(ev: WheelEvent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.document.documentElement.style.overflowY = 'hidden';
|
document.documentElement.style.overflowY = 'hidden';
|
||||||
window.document.documentElement.style.scrollBehavior = 'auto';
|
document.documentElement.style.scrollBehavior = 'auto';
|
||||||
|
|
||||||
async function deleteProfile() {
|
async function deleteProfile() {
|
||||||
if (prefer.s['deck.profile'] == null) return;
|
if (prefer.s['deck.profile'] == null) return;
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ provideMetadataReceiver((metadataGetter) => {
|
|||||||
pageMetadata.value = info;
|
pageMetadata.value = info;
|
||||||
if (pageMetadata.value) {
|
if (pageMetadata.value) {
|
||||||
if (isRoot.value && pageMetadata.value.title === instanceName) {
|
if (isRoot.value && pageMetadata.value.title === instanceName) {
|
||||||
window.document.title = pageMetadata.value.title;
|
document.title = pageMetadata.value.title;
|
||||||
} else {
|
} else {
|
||||||
window.document.title = `${pageMetadata.value.title} | ${instanceName}`;
|
document.title = `${pageMetadata.value.title} | ${instanceName}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -143,9 +143,9 @@ provideMetadataReceiver((metadataGetter) => {
|
|||||||
pageMetadata.value = info;
|
pageMetadata.value = info;
|
||||||
if (pageMetadata.value) {
|
if (pageMetadata.value) {
|
||||||
if (isRoot.value && pageMetadata.value.title === instanceName) {
|
if (isRoot.value && pageMetadata.value.title === instanceName) {
|
||||||
window.document.title = pageMetadata.value.title;
|
document.title = pageMetadata.value.title;
|
||||||
} else {
|
} else {
|
||||||
window.document.title = `${pageMetadata.value.title} | ${instanceName}`;
|
document.title = `${pageMetadata.value.title} | ${instanceName}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -170,7 +170,7 @@ if (window.innerWidth > 1024) {
|
|||||||
if (tempUI) {
|
if (tempUI) {
|
||||||
miLocalStorage.setItem('ui', tempUI);
|
miLocalStorage.setItem('ui', tempUI);
|
||||||
miLocalStorage.removeItem('ui_temp');
|
miLocalStorage.removeItem('ui_temp');
|
||||||
window.location.reload();
|
location.reload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,12 +205,12 @@ provide<Ref<number>>(CURRENT_STICKY_BOTTOM, navFooterHeight);
|
|||||||
watch(navFooter, () => {
|
watch(navFooter, () => {
|
||||||
if (navFooter.value) {
|
if (navFooter.value) {
|
||||||
navFooterHeight.value = navFooter.value.offsetHeight;
|
navFooterHeight.value = navFooter.value.offsetHeight;
|
||||||
window.document.body.style.setProperty('--MI-stickyBottom', `${navFooterHeight.value}px`);
|
document.body.style.setProperty('--MI-stickyBottom', `${navFooterHeight.value}px`);
|
||||||
window.document.body.style.setProperty('--MI-minBottomSpacing', 'var(--MI-minBottomSpacingMobile)');
|
document.body.style.setProperty('--MI-minBottomSpacing', 'var(--MI-minBottomSpacingMobile)');
|
||||||
} else {
|
} else {
|
||||||
navFooterHeight.value = 0;
|
navFooterHeight.value = 0;
|
||||||
window.document.body.style.setProperty('--MI-stickyBottom', '0px');
|
document.body.style.setProperty('--MI-stickyBottom', '0px');
|
||||||
window.document.body.style.setProperty('--MI-minBottomSpacing', '0px');
|
document.body.style.setProperty('--MI-minBottomSpacing', '0px');
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
immediate: true,
|
immediate: true,
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ provideMetadataReceiver((metadataGetter) => {
|
|||||||
pageMetadata.value = info;
|
pageMetadata.value = info;
|
||||||
if (pageMetadata.value) {
|
if (pageMetadata.value) {
|
||||||
if (isRoot.value && pageMetadata.value.title === instanceName) {
|
if (isRoot.value && pageMetadata.value.title === instanceName) {
|
||||||
window.document.title = pageMetadata.value.title;
|
document.title = pageMetadata.value.title;
|
||||||
} else {
|
} else {
|
||||||
window.document.title = `${pageMetadata.value.title} | ${instanceName}`;
|
document.title = `${pageMetadata.value.title} | ${instanceName}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ const isRoot = computed(() => mainRouter.currentRoute.value.name === 'index');
|
|||||||
|
|
||||||
const pageMetadata = ref<null | PageMetadata>(null);
|
const pageMetadata = ref<null | PageMetadata>(null);
|
||||||
|
|
||||||
const showBottom = !(new URLSearchParams(window.location.search)).has('zen') && ui === 'deck';
|
const showBottom = !(new URLSearchParams(location.search)).has('zen') && ui === 'deck';
|
||||||
|
|
||||||
provide(DI.router, mainRouter);
|
provide(DI.router, mainRouter);
|
||||||
provideMetadataReceiver((metadataGetter) => {
|
provideMetadataReceiver((metadataGetter) => {
|
||||||
@@ -45,9 +45,9 @@ provideMetadataReceiver((metadataGetter) => {
|
|||||||
pageMetadata.value = info;
|
pageMetadata.value = info;
|
||||||
if (pageMetadata.value) {
|
if (pageMetadata.value) {
|
||||||
if (isRoot.value && pageMetadata.value.title === instanceName) {
|
if (isRoot.value && pageMetadata.value.title === instanceName) {
|
||||||
window.document.title = pageMetadata.value.title;
|
document.title = pageMetadata.value.title;
|
||||||
} else {
|
} else {
|
||||||
window.document.title = `${pageMetadata.value.title} | ${instanceName}`;
|
document.title = `${pageMetadata.value.title} | ${instanceName}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ export function useNoteCapture(props: {
|
|||||||
function capture(withHandler = false): void {
|
function capture(withHandler = false): void {
|
||||||
if (connection) {
|
if (connection) {
|
||||||
// TODO: このノートがストリーミング経由で流れてきた場合のみ sr する
|
// TODO: このノートがストリーミング経由で流れてきた場合のみ sr する
|
||||||
connection.send(window.document.body.contains(props.rootEl.value ?? null as Node | null) ? 'sr' : 's', { id: note.value.id });
|
connection.send(document.body.contains(props.rootEl.value ?? null as Node | null) ? 'sr' : 's', { id: note.value.id });
|
||||||
if (pureNote.value.id !== note.value.id) connection.send('s', { id: pureNote.value.id });
|
if (pureNote.value.id !== note.value.id) connection.send('s', { id: pureNote.value.id });
|
||||||
if (withHandler) connection.on('noteUpdated', onStreamNoteUpdated);
|
if (withHandler) connection.on('noteUpdated', onStreamNoteUpdated);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export function useTooltip(
|
|||||||
if (!isHovering) return;
|
if (!isHovering) return;
|
||||||
if (elRef.value == null) return;
|
if (elRef.value == null) return;
|
||||||
const el = elRef.value instanceof Element ? elRef.value : elRef.value.$el;
|
const el = elRef.value instanceof Element ? elRef.value : elRef.value.$el;
|
||||||
if (!window.document.body.contains(el)) return; // openしようとしたときに既に元要素がDOMから消えている場合があるため
|
if (!document.body.contains(el)) return; // openしようとしたときに既に元要素がDOMから消えている場合があるため
|
||||||
|
|
||||||
const showing = ref(true);
|
const showing = ref(true);
|
||||||
onShow(showing);
|
onShow(showing);
|
||||||
@@ -38,7 +38,7 @@ export function useTooltip(
|
|||||||
};
|
};
|
||||||
|
|
||||||
autoHidingTimer = window.setInterval(() => {
|
autoHidingTimer = window.setInterval(() => {
|
||||||
if (elRef.value == null || !window.document.body.contains(elRef.value instanceof Element ? elRef.value : elRef.value.$el)) {
|
if (elRef.value == null || !document.body.contains(elRef.value instanceof Element ? elRef.value : elRef.value.$el)) {
|
||||||
if (!isHovering) return;
|
if (!isHovering) return;
|
||||||
isHovering = false;
|
isHovering = false;
|
||||||
window.clearTimeout(timeoutId);
|
window.clearTimeout(timeoutId);
|
||||||
|
|||||||
@@ -13,10 +13,8 @@ export async function clearCache() {
|
|||||||
os.waiting();
|
os.waiting();
|
||||||
miLocalStorage.removeItem('instance');
|
miLocalStorage.removeItem('instance');
|
||||||
miLocalStorage.removeItem('instanceCachedAt');
|
miLocalStorage.removeItem('instanceCachedAt');
|
||||||
//#region deprecated
|
|
||||||
miLocalStorage.removeItem('locale');
|
miLocalStorage.removeItem('locale');
|
||||||
miLocalStorage.removeItem('localeVersion');
|
miLocalStorage.removeItem('localeVersion');
|
||||||
//#endregion
|
|
||||||
miLocalStorage.removeItem('theme');
|
miLocalStorage.removeItem('theme');
|
||||||
miLocalStorage.removeItem('emojis');
|
miLocalStorage.removeItem('emojis');
|
||||||
miLocalStorage.removeItem('lastEmojisFetchedAt');
|
miLocalStorage.removeItem('lastEmojisFetchedAt');
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ function releaseFocusTrap(el: HTMLElement): void {
|
|||||||
|
|
||||||
const highestZIndexElement = getHighestZIndexElement();
|
const highestZIndexElement = getHighestZIndexElement();
|
||||||
|
|
||||||
if (el.parentElement != null && el !== window.document.body) {
|
if (el.parentElement != null && el !== document.body) {
|
||||||
el.parentElement.childNodes.forEach((siblingNode) => {
|
el.parentElement.childNodes.forEach((siblingNode) => {
|
||||||
const siblingEl = getHTMLElementOrNull(siblingNode);
|
const siblingEl = getHTMLElementOrNull(siblingNode);
|
||||||
if (!siblingEl) return;
|
if (!siblingEl) return;
|
||||||
@@ -104,7 +104,7 @@ export function focusTrap(el: HTMLElement, hasInteractionWithOtherFocusTrappedEl
|
|||||||
el.inert = false;
|
el.inert = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (el.parentElement != null && el !== window.document.body) {
|
if (el.parentElement != null && el !== document.body) {
|
||||||
el.parentElement.childNodes.forEach((siblingNode) => {
|
el.parentElement.childNodes.forEach((siblingNode) => {
|
||||||
const siblingEl = getHTMLElementOrNull(siblingNode);
|
const siblingEl = getHTMLElementOrNull(siblingNode);
|
||||||
if (!siblingEl) return;
|
if (!siblingEl) return;
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export const focusParent = (input: MaybeHTMLElement | null | undefined, self = f
|
|||||||
|
|
||||||
const focusOrScroll = (element: HTMLElement, scroll: boolean) => {
|
const focusOrScroll = (element: HTMLElement, scroll: boolean) => {
|
||||||
if (scroll) {
|
if (scroll) {
|
||||||
const scrollContainer = getScrollContainer(element) ?? window.document.documentElement;
|
const scrollContainer = getScrollContainer(element) ?? document.documentElement;
|
||||||
const scrollContainerTop = getScrollPosition(scrollContainer);
|
const scrollContainerTop = getScrollPosition(scrollContainer);
|
||||||
const stickyTop = getStickyTop(element, scrollContainer);
|
const stickyTop = getStickyTop(element, scrollContainer);
|
||||||
const stickyBottom = getStickyBottom(element, scrollContainer);
|
const stickyBottom = getStickyBottom(element, scrollContainer);
|
||||||
@@ -74,7 +74,7 @@ const focusOrScroll = (element: HTMLElement, scroll: boolean) => {
|
|||||||
scrollContainer.scrollTo({ top: scrollTo, behavior: 'instant' });
|
scrollContainer.scrollTo({ top: scrollTo, behavior: 'instant' });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.document.activeElement !== element) {
|
if (document.activeElement !== element) {
|
||||||
element.focus({ preventScroll: true });
|
element.focus({ preventScroll: true });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ export const requestFullscreen = ({ videoEl, playerEl, options }: RequestFullscr
|
|||||||
|
|
||||||
export const exitFullscreen = ({ videoEl }: ExitFullscreenProps) => {
|
export const exitFullscreen = ({ videoEl }: ExitFullscreenProps) => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
if (window.document.exitFullscreen != null) {
|
if (document.exitFullscreen != null) {
|
||||||
window.document.exitFullscreen();
|
document.exitFullscreen();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (videoEl.webkitExitFullscreen != null) {
|
if (videoEl.webkitExitFullscreen != null) {
|
||||||
|
|||||||
@@ -54,9 +54,9 @@ export const makeHotkey = (keymap: Keymap) => {
|
|||||||
const actions = parseKeymap(keymap);
|
const actions = parseKeymap(keymap);
|
||||||
return (ev: KeyboardEvent) => {
|
return (ev: KeyboardEvent) => {
|
||||||
if ('pswp' in window && window.pswp != null) return;
|
if ('pswp' in window && window.pswp != null) return;
|
||||||
if (window.document.activeElement != null) {
|
if (document.activeElement != null) {
|
||||||
if (IGNORE_ELEMENTS.includes(window.document.activeElement.tagName.toLowerCase())) return;
|
if (IGNORE_ELEMENTS.includes(document.activeElement.tagName.toLowerCase())) return;
|
||||||
if (getHTMLElementOrNull(window.document.activeElement)?.isContentEditable) return;
|
if (getHTMLElementOrNull(document.activeElement)?.isContentEditable) return;
|
||||||
}
|
}
|
||||||
for (const action of actions) {
|
for (const action of actions) {
|
||||||
if (matchPatterns(ev, action)) {
|
if (matchPatterns(ev, action)) {
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export function initChart() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// フォントカラー
|
// フォントカラー
|
||||||
Chart.defaults.color = getComputedStyle(window.document.documentElement).getPropertyValue('--MI_THEME-fg');
|
Chart.defaults.color = getComputedStyle(document.documentElement).getPropertyValue('--MI_THEME-fg');
|
||||||
|
|
||||||
Chart.defaults.borderColor = store.s.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)';
|
Chart.defaults.borderColor = store.s.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)';
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export function physics(container: HTMLElement) {
|
|||||||
// create renderer
|
// create renderer
|
||||||
const render = Matter.Render.create({
|
const render = Matter.Render.create({
|
||||||
engine: engine,
|
engine: engine,
|
||||||
//element: window.document.getElementById('debug'),
|
//element: document.getElementById('debug'),
|
||||||
options: {
|
options: {
|
||||||
width: containerWidth,
|
width: containerWidth,
|
||||||
height: containerHeight,
|
height: containerHeight,
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
const CHARS = 'abcdefghijklmnopqrstuvwxyz'; // CSSの<custom-ident>などで使われることもあるのでa-z以外使うな
|
|
||||||
|
|
||||||
export function randomId(length = 32, characters = CHARS) {
|
|
||||||
let result = '';
|
|
||||||
const charactersLength = characters.length;
|
|
||||||
for ( let i = 0; i < length; i++ ) {
|
|
||||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -35,6 +35,6 @@ export async function reloadAsk(opts: {
|
|||||||
if (opts.unison) {
|
if (opts.unison) {
|
||||||
unisonReload();
|
unisonReload();
|
||||||
} else {
|
} else {
|
||||||
window.location.reload();
|
location.reload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user