Merge branch 'develop' into enh-15290

This commit is contained in:
かっこかり 2025-03-21 18:36:36 +09:00 committed by GitHub
commit 3d24a6e98f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
160 changed files with 575 additions and 532 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "misskey", "name": "misskey",
"version": "2025.3.2-beta.6", "version": "2025.3.2-beta.8",
"codename": "nasubi", "codename": "nasubi",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -131,7 +131,7 @@ export function imageDataUrl(options?: {
alpha?: number, alpha?: number,
} }
}, seed?: string): string { }, seed?: string): string {
const canvas = document.createElement('canvas'); const canvas = window.document.createElement('canvas');
canvas.width = options?.size?.width ?? 100; canvas.width = options?.size?.width ?? 100;
canvas.height = options?.size?.height ?? 100; canvas.height = options?.size?.height ?? 100;

View File

@ -23,9 +23,9 @@ let misskeyOS = null;
function loadTheme(applyTheme: typeof import('../src/theme')['applyTheme']) { function loadTheme(applyTheme: typeof import('../src/theme')['applyTheme']) {
unobserve(); unobserve();
const theme = themes[document.documentElement.dataset.misskeyTheme]; const theme = themes[window.document.documentElement.dataset.misskeyTheme];
if (theme) { if (theme) {
applyTheme(themes[document.documentElement.dataset.misskeyTheme]); applyTheme(themes[window.document.documentElement.dataset.misskeyTheme]);
} else { } else {
applyTheme(themes['l-light']); applyTheme(themes['l-light']);
} }
@ -42,7 +42,7 @@ function loadTheme(applyTheme: typeof import('../src/theme')['applyTheme']) {
} }
} }
}); });
observer.observe(document.documentElement, { observer.observe(window.document.documentElement, {
attributes: true, attributes: true,
attributeFilter: ['data-misskey-theme'], attributeFilter: ['data-misskey-theme'],
}); });

View File

@ -56,7 +56,9 @@ export default [
// open ... window.openと衝突 or 紛らわしい // open ... window.openと衝突 or 紛らわしい
// fetch ... window.fetchと衝突 or 紛らわしい // fetch ... window.fetchと衝突 or 紛らわしい
// location ... window.locationと衝突 or 紛らわしい // location ... window.locationと衝突 or 紛らわしい
'id-denylist': ['warn', 'window', 'e', 'close', 'open', 'fetch', 'location'], // document ... window.documentと衝突 or 紛らわしい
// history ... window.historyと衝突 or 紛らわしい
'id-denylist': ['warn', 'window', 'e', 'close', 'open', 'fetch', 'location', 'document', 'history'],
'no-restricted-globals': [ 'no-restricted-globals': [
'error', 'error',
{ {
@ -75,10 +77,18 @@ export default [
'name': 'location', 'name': 'location',
'message': 'Use `window.location`.', 'message': 'Use `window.location`.',
}, },
{
'name': 'document',
'message': 'Use `window.document`.',
},
{ {
'name': 'history', 'name': 'history',
'message': 'Use `window.history`.', 'message': 'Use `window.history`.',
}, },
{
'name': 'name',
'message': 'Use `window.name`. もしくは name という変数名を定義し忘れている',
},
], ],
'no-shadow': ['warn'], 'no-shadow': ['warn'],
'vue/attributes-order': ['error', { 'vue/attributes-order': ['error', {

View File

@ -14,7 +14,7 @@ import { subBoot } from '@/boot/sub-boot.js';
const subBootPaths = ['/share', '/auth', '/miauth', '/oauth', '/signup-complete', '/install-extensions']; const subBootPaths = ['/share', '/auth', '/miauth', '/oauth', '/signup-complete', '/install-extensions'];
if (subBootPaths.some(i => location.pathname === i || location.pathname.startsWith(i + '/'))) { if (subBootPaths.some(i => window.location.pathname === i || window.location.pathname.startsWith(i + '/'))) {
subBoot(); subBoot();
} else { } else {
mainBoot(); mainBoot();

View File

@ -191,7 +191,7 @@ export async function login(token: AccountWithToken['token'], redirect?: string)
// 他のタブは再読み込みするだけ // 他のタブは再読み込みするだけ
reloadChannel.postMessage(null); reloadChannel.postMessage(null);
// このページはredirectで指定された先に移動 // このページはredirectで指定された先に移動
location.href = redirect; window.location.href = redirect;
return; return;
} }

View File

@ -95,28 +95,28 @@ export async function common(createVue: () => App<Element>) {
//#endregion //#endregion
// タッチデバイスでCSSの:hoverを機能させる // タッチデバイスでCSSの:hoverを機能させる
document.addEventListener('touchend', () => {}, { passive: true }); window.document.addEventListener('touchend', () => {}, { passive: true });
// URLに#pswpを含む場合は取り除く // URLに#pswpを含む場合は取り除く
if (location.hash === '#pswp') { if (window.location.hash === '#pswp') {
history.replaceState(null, '', location.href.replace('#pswp', '')); window.history.replaceState(null, '', window.location.href.replace('#pswp', ''));
} }
// 一斉リロード // 一斉リロード
reloadChannel.addEventListener('message', path => { reloadChannel.addEventListener('message', path => {
if (path !== null) location.href = path; if (path !== null) window.location.href = path;
else location.reload(); else window.location.reload();
}); });
// If mobile, insert the viewport meta tag // If mobile, insert the viewport meta tag
if (['smartphone', 'tablet'].includes(deviceKind)) { if (['smartphone', 'tablet'].includes(deviceKind)) {
const viewport = document.getElementsByName('viewport').item(0); const viewport = window.document.getElementsByName('viewport').item(0);
viewport.setAttribute('content', viewport.setAttribute('content',
`${viewport.getAttribute('content')}, minimum-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover`); `${viewport.getAttribute('content')}, minimum-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover`);
} }
//#region Set lang attr //#region Set lang attr
const html = document.documentElement; const html = window.document.documentElement;
html.setAttribute('lang', lang); html.setAttribute('lang', lang);
//#endregion //#endregion
@ -130,11 +130,11 @@ export async function common(createVue: () => App<Element>) {
}); });
//#region loginId //#region loginId
const params = new URLSearchParams(location.search); const params = new URLSearchParams(window.location.search);
const loginId = params.get('loginId'); const loginId = params.get('loginId');
if (loginId) { if (loginId) {
const target = getUrlWithoutLoginId(location.href); const target = getUrlWithoutLoginId(window.location.href);
if (!$i || $i.id !== loginId) { if (!$i || $i.id !== loginId) {
const account = await getAccountFromId(loginId); const account = await getAccountFromId(loginId);
@ -143,7 +143,7 @@ export async function common(createVue: () => App<Element>) {
} }
} }
history.replaceState({ misskey: 'loginId' }, '', target); window.history.replaceState({ misskey: 'loginId' }, '', target);
} }
//#endregion //#endregion
@ -155,7 +155,7 @@ export async function common(createVue: () => App<Element>) {
); );
}, { immediate: miLocalStorage.getItem('theme') == null }); }, { immediate: miLocalStorage.getItem('theme') == null });
document.documentElement.dataset.colorScheme = store.s.darkMode ? 'dark' : 'light'; window.document.documentElement.dataset.colorScheme = store.s.darkMode ? 'dark' : 'light';
const darkTheme = prefer.model('darkTheme'); const darkTheme = prefer.model('darkTheme');
const lightTheme = prefer.model('lightTheme'); const lightTheme = prefer.model('lightTheme');
@ -201,20 +201,20 @@ export async function common(createVue: () => App<Element>) {
}, { immediate: true }); }, { immediate: true });
watch(prefer.r.useBlurEffectForModal, v => { watch(prefer.r.useBlurEffectForModal, v => {
document.documentElement.style.setProperty('--MI-modalBgFilter', v ? 'blur(4px)' : 'none'); window.document.documentElement.style.setProperty('--MI-modalBgFilter', v ? 'blur(4px)' : 'none');
}, { immediate: true }); }, { immediate: true });
watch(prefer.r.useBlurEffect, v => { watch(prefer.r.useBlurEffect, v => {
if (v) { if (v) {
document.documentElement.style.removeProperty('--MI-blur'); window.document.documentElement.style.removeProperty('--MI-blur');
} else { } else {
document.documentElement.style.setProperty('--MI-blur', 'none'); window.document.documentElement.style.setProperty('--MI-blur', 'none');
} }
}, { immediate: true }); }, { immediate: true });
// Keep screen on // Keep screen on
const onVisibilityChange = () => document.addEventListener('visibilitychange', () => { const onVisibilityChange = () => window.document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') { if (window.document.visibilityState === 'visible') {
navigator.wakeLock.request('screen'); navigator.wakeLock.request('screen');
} }
}); });
@ -224,7 +224,7 @@ export async function common(createVue: () => App<Element>) {
.catch(() => { .catch(() => {
// On WebKit-based browsers, user activation is required to send wake lock request // On WebKit-based browsers, user activation is required to send wake lock request
// https://webkit.org/blog/13862/the-user-activation-api/ // https://webkit.org/blog/13862/the-user-activation-api/
document.addEventListener( window.document.addEventListener(
'click', 'click',
() => navigator.wakeLock.request('screen').then(onVisibilityChange), () => navigator.wakeLock.request('screen').then(onVisibilityChange),
{ once: true }, { once: true },
@ -233,7 +233,7 @@ export async function common(createVue: () => App<Element>) {
} }
if (prefer.s.makeEveryTextElementsSelectable) { if (prefer.s.makeEveryTextElementsSelectable) {
document.documentElement.classList.add('forceSelectableAll'); window.document.documentElement.classList.add('forceSelectableAll');
} }
//#region Fetch user //#region Fetch user
@ -278,16 +278,16 @@ export async function common(createVue: () => App<Element>) {
const rootEl = ((): HTMLElement => { const rootEl = ((): HTMLElement => {
const MISSKEY_MOUNT_DIV_ID = 'misskey_app'; const MISSKEY_MOUNT_DIV_ID = 'misskey_app';
const currentRoot = document.getElementById(MISSKEY_MOUNT_DIV_ID); const currentRoot = window.document.getElementById(MISSKEY_MOUNT_DIV_ID);
if (currentRoot) { if (currentRoot) {
console.warn('multiple import detected'); console.warn('multiple import detected');
return currentRoot; return currentRoot;
} }
const root = document.createElement('div'); const root = window.document.createElement('div');
root.id = MISSKEY_MOUNT_DIV_ID; root.id = MISSKEY_MOUNT_DIV_ID;
document.body.appendChild(root); window.document.body.appendChild(root);
return root; return root;
})(); })();
@ -330,7 +330,7 @@ export async function common(createVue: () => App<Element>) {
} }
function removeSplash() { function removeSplash() {
const splash = document.getElementById('splash'); const splash = window.document.getElementById('splash');
if (splash) { if (splash) {
splash.style.opacity = '0'; splash.style.opacity = '0';
splash.style.pointerEvents = 'none'; splash.style.pointerEvents = 'none';

View File

@ -43,7 +43,7 @@ export async function mainBoot() {
if (!$i) uiStyle = 'visitor'; if (!$i) uiStyle = 'visitor';
if (searchParams.has('zen')) uiStyle = 'zen'; if (searchParams.has('zen')) uiStyle = 'zen';
if (uiStyle === 'deck' && prefer.s['deck.useSimpleUiForNonRootPages'] && location.pathname !== '/') uiStyle = 'zen'; if (uiStyle === 'deck' && prefer.s['deck.useSimpleUiForNonRootPages'] && window.location.pathname !== '/') uiStyle = 'zen';
if (searchParams.has('ui')) uiStyle = searchParams.get('ui'); if (searchParams.has('ui')) uiStyle = searchParams.get('ui');
@ -216,7 +216,7 @@ export async function mainBoot() {
let reloadDialogShowing = false; let reloadDialogShowing = false;
stream.on('_disconnected_', async () => { stream.on('_disconnected_', async () => {
if (prefer.s.serverDisconnectedBehavior === 'reload') { if (prefer.s.serverDisconnectedBehavior === 'reload') {
location.reload(); window.location.reload();
} else if (prefer.s.serverDisconnectedBehavior === 'dialog') { } else if (prefer.s.serverDisconnectedBehavior === 'dialog') {
if (reloadDialogShowing) return; if (reloadDialogShowing) return;
reloadDialogShowing = true; reloadDialogShowing = true;
@ -227,7 +227,7 @@ export async function mainBoot() {
}); });
reloadDialogShowing = false; reloadDialogShowing = false;
if (!canceled) { if (!canceled) {
location.reload(); window.location.reload();
} }
} }
}); });
@ -398,7 +398,7 @@ export async function mainBoot() {
let lastVisibilityChangedAt = Date.now(); let lastVisibilityChangedAt = Date.now();
function claimPlainLucky() { function claimPlainLucky() {
if (document.visibilityState !== 'visible') { if (window.document.visibilityState !== 'visible') {
if (justPlainLuckyTimer != null) window.clearTimeout(justPlainLuckyTimer); if (justPlainLuckyTimer != null) window.clearTimeout(justPlainLuckyTimer);
return; return;
} }
@ -413,7 +413,7 @@ export async function mainBoot() {
window.addEventListener('visibilitychange', () => { window.addEventListener('visibilitychange', () => {
const now = Date.now(); const now = Date.now();
if (document.visibilityState === 'visible') { if (window.document.visibilityState === 'visible') {
// タブを高速で切り替えたら取得処理が何度も走るのを防ぐ // タブを高速で切り替えたら取得処理が何度も走るのを防ぐ
if ((now - lastVisibilityChangedAt) < 1000 * 10) { if ((now - lastVisibilityChangedAt) < 1000 * 10) {
justPlainLuckyTimer = window.setTimeout(claimPlainLucky, 1000 * 10); justPlainLuckyTimer = window.setTimeout(claimPlainLucky, 1000 * 10);
@ -458,7 +458,7 @@ export async function mainBoot() {
const latestDonationInfoShownAt = miLocalStorage.getItem('latestDonationInfoShownAt'); const latestDonationInfoShownAt = miLocalStorage.getItem('latestDonationInfoShownAt');
const neverShowDonationInfo = miLocalStorage.getItem('neverShowDonationInfo'); const neverShowDonationInfo = miLocalStorage.getItem('neverShowDonationInfo');
if (neverShowDonationInfo !== 'true' && (createdAt.getTime() < (Date.now() - (1000 * 60 * 60 * 24 * 3))) && !location.pathname.startsWith('/miauth')) { if (neverShowDonationInfo !== 'true' && (createdAt.getTime() < (Date.now() - (1000 * 60 * 60 * 24 * 3))) && !window.location.pathname.startsWith('/miauth')) {
if (latestDonationInfoShownAt == null || (new Date(latestDonationInfoShownAt).getTime() < (Date.now() - (1000 * 60 * 60 * 24 * 30)))) { if (latestDonationInfoShownAt == null || (new Date(latestDonationInfoShownAt).getTime() < (Date.now() - (1000 * 60 * 60 * 24 * 30)))) {
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkDonation.vue')), {}, { const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkDonation.vue')), {}, {
closed: () => dispose(), closed: () => dispose(),
@ -554,7 +554,7 @@ export async function mainBoot() {
mainRouter.push('/search'); mainRouter.push('/search');
}, },
} as const satisfies Keymap; } as const satisfies Keymap;
document.addEventListener('keydown', makeHotkey(keymap), { passive: false }); window.document.addEventListener('keydown', makeHotkey(keymap), { passive: false });
initializeSw(); initializeSw();
} }

View File

@ -192,7 +192,7 @@ function tick() {
tick(); tick();
function calcColors() { function calcColors() {
const computedStyle = getComputedStyle(document.documentElement); const computedStyle = getComputedStyle(window.document.documentElement);
const dark = tinycolor(computedStyle.getPropertyValue('--MI_THEME-bg')).isDark(); const dark = tinycolor(computedStyle.getPropertyValue('--MI_THEME-bg')).isDark();
const accent = tinycolor(computedStyle.getPropertyValue('--MI_THEME-accent')).toHexString(); const accent = tinycolor(computedStyle.getPropertyValue('--MI_THEME-accent')).toHexString();
majorGraduationColor.value = dark ? 'rgba(255, 255, 255, 0.3)' : 'rgba(0, 0, 0, 0.3)'; majorGraduationColor.value = dark ? 'rgba(255, 255, 255, 0.3)' : 'rgba(0, 0, 0, 0.3)';

View File

@ -359,7 +359,7 @@ onMounted(() => {
props.textarea.addEventListener('keydown', onKeydown); props.textarea.addEventListener('keydown', onKeydown);
document.body.addEventListener('mousedown', onMousedown); window.document.body.addEventListener('mousedown', onMousedown);
nextTick(() => { nextTick(() => {
exec(); exec();
@ -375,7 +375,7 @@ onMounted(() => {
onBeforeUnmount(() => { onBeforeUnmount(() => {
props.textarea.removeEventListener('keydown', onKeydown); props.textarea.removeEventListener('keydown', onKeydown);
document.body.removeEventListener('mousedown', onMousedown); window.document.body.removeEventListener('mousedown', onMousedown);
}); });
</script> </script>

View File

@ -92,7 +92,7 @@ function onMousedown(evt: MouseEvent): void {
const target = evt.target! as HTMLElement; const target = evt.target! as HTMLElement;
const rect = target.getBoundingClientRect(); const rect = target.getBoundingClientRect();
const ripple = document.createElement('div'); const ripple = window.document.createElement('div');
ripple.classList.add(ripples.value!.dataset.childrenClass!); ripple.classList.add(ripples.value!.dataset.childrenClass!);
ripple.style.top = (evt.clientY - rect.top - 1).toString() + 'px'; ripple.style.top = (evt.clientY - rect.top - 1).toString() + 'px';
ripple.style.left = (evt.clientX - rect.left - 1).toString() + 'px'; ripple.style.left = (evt.clientX - rect.left - 1).toString() + 'px';

View File

@ -112,7 +112,7 @@ watch(() => [props.instanceUrl, props.sitekey, props.secretKey], async () => {
if (loaded || props.provider === 'mcaptcha' || props.provider === 'testcaptcha') { if (loaded || props.provider === 'mcaptcha' || props.provider === 'testcaptcha') {
available.value = true; available.value = true;
} else if (src.value !== null) { } else if (src.value !== null) {
(document.getElementById(scriptId.value) ?? document.head.appendChild(Object.assign(document.createElement('script'), { (window.document.getElementById(scriptId.value) ?? window.document.head.appendChild(Object.assign(window.document.createElement('script'), {
async: true, async: true,
id: scriptId.value, id: scriptId.value,
src: src.value, src: src.value,
@ -149,7 +149,7 @@ async function requestRender() {
if (captcha.value.render && captchaEl.value instanceof Element && props.sitekey) { if (captcha.value.render && captchaEl.value instanceof Element && props.sitekey) {
// reCAPTCHAcaptchaEldiv. // reCAPTCHAcaptchaEldiv.
// divrenderreCAPTCHA // divrenderreCAPTCHA
const elem = document.createElement('div'); const elem = window.document.createElement('div');
captchaEl.value.appendChild(elem); captchaEl.value.appendChild(elem);
captchaWidgetId.value = captcha.value.render(elem, { captchaWidgetId.value = captcha.value.render(elem, {
@ -174,7 +174,7 @@ async function requestRender() {
function clearWidget() { function clearWidget() {
if (props.provider === 'mcaptcha') { if (props.provider === 'mcaptcha') {
const container = document.getElementById('mcaptcha__widget-container'); const container = window.document.getElementById('mcaptcha__widget-container');
if (container) { if (container) {
container.innerHTML = ''; container.innerHTML = '';
} }

View File

@ -68,11 +68,11 @@ onMounted(() => {
rootEl.value.style.left = `${left}px`; rootEl.value.style.left = `${left}px`;
} }
document.body.addEventListener('mousedown', onMousedown); window.document.body.addEventListener('mousedown', onMousedown);
}); });
onBeforeUnmount(() => { onBeforeUnmount(() => {
document.body.removeEventListener('mousedown', onMousedown); window.document.body.removeEventListener('mousedown', onMousedown);
}); });
function onMousedown(evt: Event) { function onMousedown(evt: Event) {

View File

@ -3,14 +3,12 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable import/no-default-export */
import type { StoryObj } from '@storybook/vue3';
import { HttpResponse, http } from 'msw'; import { HttpResponse, http } from 'msw';
import { action } from '@storybook/addon-actions'; import { action } from '@storybook/addon-actions';
import { file } from '../../.storybook/fakes.js'; import { file } from '../../.storybook/fakes.js';
import { commonHandlers } from '../../.storybook/mocks.js'; import { commonHandlers } from '../../.storybook/mocks.js';
import MkCropperDialog from './MkCropperDialog.vue'; import MkCropperDialog from './MkCropperDialog.vue';
import type { StoryObj } from '@storybook/vue3';
export const Default = { export const Default = {
render(args) { render(args) {
return { return {
@ -55,7 +53,7 @@ export const Default = {
http.get('/proxy/image.webp', async ({ request }) => { http.get('/proxy/image.webp', async ({ request }) => {
const url = new URL(request.url).searchParams.get('url'); const url = new URL(request.url).searchParams.get('url');
if (url === 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true') { if (url === 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true') {
const image = await (await fetch('client-assets/fedi.jpg')).blob(); const image = await (await window.fetch('client-assets/fedi.jpg')).blob();
return new HttpResponse(image, { return new HttpResponse(image, {
headers: { headers: {
'Content-Type': 'image/jpeg', 'Content-Type': 'image/jpeg',

View File

@ -122,7 +122,7 @@ onMounted(() => {
cropper = new Cropper(imgEl.value!, { cropper = new Cropper(imgEl.value!, {
}); });
const computedStyle = getComputedStyle(document.documentElement); const computedStyle = getComputedStyle(window.document.documentElement);
const selection = cropper.getCropperSelection()!; const selection = cropper.getCropperSelection()!;
selection.themeColor = tinycolor(computedStyle.getPropertyValue('--MI_THEME-accent')).toHexString(); selection.themeColor = tinycolor(computedStyle.getPropertyValue('--MI_THEME-accent')).toHexString();

View File

@ -180,7 +180,7 @@ function applyToPreview() {
nextTick(() => { nextTick(() => {
if (currentPreviewUrl === embedPreviewUrl.value) { if (currentPreviewUrl === embedPreviewUrl.value) {
// URL // URL
iframeEl.value?.contentWindow?.location.reload(); iframeEl.value?.contentWindow?.window.location.reload();
} }
}); });
} }

View File

@ -116,7 +116,7 @@ function toggle() {
} }
onMounted(() => { onMounted(() => {
const computedStyle = getComputedStyle(document.documentElement); const computedStyle = getComputedStyle(window.document.documentElement);
const parentBg = getBgColor(rootEl.value?.parentElement) ?? 'transparent'; const parentBg = getBgColor(rootEl.value?.parentElement) ?? 'transparent';
const myBg = computedStyle.getPropertyValue('--MI_THEME-panel'); const myBg = computedStyle.getPropertyValue('--MI_THEME-panel');
bgSame.value = parentBg === myBg; bgSame.value = parentBg === myBg;

View File

@ -19,9 +19,9 @@ SPDX-License-Identifier: AGPL-3.0-only
:leaveToClass="transitionName === 'swipeAnimationLeft' ? $style.swipeAnimationLeft_leaveTo : $style.swipeAnimationRight_leaveTo" :leaveToClass="transitionName === 'swipeAnimationLeft' ? $style.swipeAnimationLeft_leaveTo : $style.swipeAnimationRight_leaveTo"
:style="`--swipe: ${pullDistance}px;`" :style="`--swipe: ${pullDistance}px;`"
> >
<!-- 注意slot内の最上位要素に動的にkeyを設定すること --> <div :key="tabModel">
<!-- 各最上位要素にユニークなkeyの指定がないとTransitionがうまく動きません -->
<slot></slot> <slot></slot>
</div>
</Transition> </Transition>
</div> </div>
</template> </template>

View File

@ -55,7 +55,7 @@ import { extractAvgColorFromBlurhash } from '@@/js/extract-avg-color-from-blurha
const canvasPromise = new Promise<WorkerMultiDispatch | HTMLCanvasElement>(resolve => { const canvasPromise = new Promise<WorkerMultiDispatch | HTMLCanvasElement>(resolve => {
// Web Worker // Web Worker
if (import.meta.env.MODE === 'test') { if (import.meta.env.MODE === 'test') {
const canvas = document.createElement('canvas'); const canvas = window.document.createElement('canvas');
canvas.width = 64; canvas.width = 64;
canvas.height = 64; canvas.height = 64;
resolve(canvas); resolve(canvas);
@ -70,7 +70,7 @@ const canvasPromise = new Promise<WorkerMultiDispatch | HTMLCanvasElement>(resol
); );
resolve(workers); resolve(workers);
} else { } else {
const canvas = document.createElement('canvas'); const canvas = window.document.createElement('canvas');
canvas.width = 64; canvas.width = 64;
canvas.height = 64; canvas.height = 64;
resolve(canvas); resolve(canvas);

View File

@ -3,13 +3,12 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
/* eslint-disable @typescript-eslint/explicit-function-return-type */
import type { StoryObj } from '@storybook/vue3';
import { HttpResponse, http } from 'msw'; import { HttpResponse, http } from 'msw';
import { federationInstance } from '../../.storybook/fakes.js'; import { federationInstance } from '../../.storybook/fakes.js';
import { commonHandlers } from '../../.storybook/mocks.js'; import { commonHandlers } from '../../.storybook/mocks.js';
import { getChartResolver } from '../../.storybook/charts.js'; import { getChartResolver } from '../../.storybook/charts.js';
import MkInstanceCardMini from './MkInstanceCardMini.vue'; import MkInstanceCardMini from './MkInstanceCardMini.vue';
import type { StoryObj } from '@storybook/vue3';
export const Default = { export const Default = {
render(args) { render(args) {
@ -48,7 +47,7 @@ export const Default = {
const url = new URL(urlStr); const url = new URL(urlStr);
if (url.href.startsWith('https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/')) { if (url.href.startsWith('https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/')) {
const image = await (await fetch(`client-assets/${url.pathname.split('/').pop()}`)).blob(); const image = await (await window.fetch(`client-assets/${url.pathname.split('/').pop()}`)).blob();
return new HttpResponse(image, { return new HttpResponse(image, {
headers: { headers: {
'Content-Type': 'image/jpeg', 'Content-Type': 'image/jpeg',

View File

@ -126,7 +126,7 @@ function createDoughnut(chartEl, tooltip, data) {
labels: data.map(x => x.name), labels: data.map(x => x.name),
datasets: [{ datasets: [{
backgroundColor: data.map(x => x.color), backgroundColor: data.map(x => x.color),
borderColor: getComputedStyle(document.documentElement).getPropertyValue('--MI_THEME-panel'), borderColor: getComputedStyle(window.document.documentElement).getPropertyValue('--MI_THEME-panel'),
borderWidth: 2, borderWidth: 2,
hoverOffset: 0, hoverOffset: 0,
data: data.map(x => x.value), data: data.map(x => x.value),

View File

@ -148,7 +148,7 @@ const keymap = {
// PlayerEl // PlayerEl
function hasFocus() { function hasFocus() {
if (!playerEl.value) return false; if (!playerEl.value) return false;
return playerEl.value === document.activeElement || playerEl.value.contains(document.activeElement); return playerEl.value === window.document.activeElement || playerEl.value.contains(window.document.activeElement);
} }
const playerEl = useTemplateRef('playerEl'); const playerEl = useTemplateRef('playerEl');

View File

@ -48,7 +48,7 @@ const props = defineProps<{
const gallery = useTemplateRef('gallery'); const gallery = useTemplateRef('gallery');
const pswpZIndex = os.claimZIndex('middle'); const pswpZIndex = os.claimZIndex('middle');
document.documentElement.style.setProperty('--mk-pswp-root-z-index', pswpZIndex.toString()); window.document.documentElement.style.setProperty('--mk-pswp-root-z-index', pswpZIndex.toString());
const count = computed(() => props.mediaList.filter(media => previewable(media)).length); const count = computed(() => props.mediaList.filter(media => previewable(media)).length);
let lightbox: PhotoSwipeLightbox | null = null; let lightbox: PhotoSwipeLightbox | null = null;
@ -166,7 +166,7 @@ onMounted(() => {
className: 'pswp__alt-text-container', className: 'pswp__alt-text-container',
appendTo: 'wrapper', appendTo: 'wrapper',
onInit: (el, pswp) => { onInit: (el, pswp) => {
const textBox = document.createElement('p'); const textBox = window.document.createElement('p');
textBox.className = 'pswp__alt-text _acrylic'; textBox.className = 'pswp__alt-text _acrylic';
el.appendChild(textBox); el.appendChild(textBox);
@ -178,19 +178,19 @@ onMounted(() => {
}); });
lightbox.on('afterInit', () => { lightbox.on('afterInit', () => {
activeEl = document.activeElement instanceof HTMLElement ? document.activeElement : null; activeEl = window.document.activeElement instanceof HTMLElement ? window.document.activeElement : null;
focusParent(activeEl, true, true); focusParent(activeEl, true, true);
lightbox?.pswp?.element?.focus({ lightbox?.pswp?.element?.focus({
preventScroll: true, preventScroll: true,
}); });
history.pushState(null, '', '#pswp'); window.history.pushState(null, '', '#pswp');
}); });
lightbox.on('destroy', () => { lightbox.on('destroy', () => {
focusParent(activeEl, true, false); focusParent(activeEl, true, false);
activeEl = null; activeEl = null;
if (window.location.hash === '#pswp') { if (window.location.hash === '#pswp') {
history.back(); window.history.back();
} }
}); });

View File

@ -171,7 +171,7 @@ const keymap = {
// PlayerEl // PlayerEl
function hasFocus() { function hasFocus() {
if (!playerEl.value) return false; if (!playerEl.value) return false;
return playerEl.value === document.activeElement || playerEl.value.contains(document.activeElement); return playerEl.value === window.document.activeElement || playerEl.value.contains(window.document.activeElement);
} }
// eslint-disable-next-line vue/no-setup-props-reactivity-loss // eslint-disable-next-line vue/no-setup-props-reactivity-loss
@ -216,7 +216,7 @@ function showMenu(ev: MouseEvent) {
'2.0x': 2, '2.0x': 2,
}, },
}, },
...(document.pictureInPictureEnabled ? [{ ...(window.document.pictureInPictureEnabled ? [{
text: i18n.ts._mediaControls.pip, text: i18n.ts._mediaControls.pip,
icon: 'ti ti-picture-in-picture', icon: 'ti ti-picture-in-picture',
action: togglePictureInPicture, action: togglePictureInPicture,
@ -384,8 +384,8 @@ function toggleFullscreen() {
function togglePictureInPicture() { function togglePictureInPicture() {
if (videoEl.value) { if (videoEl.value) {
if (document.pictureInPictureElement) { if (window.document.pictureInPictureElement) {
document.exitPictureInPicture(); window.document.exitPictureInPicture();
} else { } else {
videoEl.value.requestPictureInPicture(); videoEl.value.requestPictureInPicture();
} }

View File

@ -358,10 +358,10 @@ function switchItem(item: MenuSwitch & { ref: any }) {
function focusUp() { function focusUp() {
if (disposed) return; if (disposed) return;
if (!itemsEl.value?.contains(document.activeElement)) return; if (!itemsEl.value?.contains(window.document.activeElement)) return;
const focusableElements = Array.from(itemsEl.value.children).filter(isFocusable); const focusableElements = Array.from(itemsEl.value.children).filter(isFocusable);
const activeIndex = focusableElements.findIndex(el => el === document.activeElement); const activeIndex = focusableElements.findIndex(el => el === window.document.activeElement);
const targetIndex = (activeIndex !== -1 && activeIndex !== 0) ? (activeIndex - 1) : (focusableElements.length - 1); const targetIndex = (activeIndex !== -1 && activeIndex !== 0) ? (activeIndex - 1) : (focusableElements.length - 1);
const targetElement = focusableElements.at(targetIndex) ?? itemsEl.value; const targetElement = focusableElements.at(targetIndex) ?? itemsEl.value;
@ -370,10 +370,10 @@ function focusUp() {
function focusDown() { function focusDown() {
if (disposed) return; if (disposed) return;
if (!itemsEl.value?.contains(document.activeElement)) return; if (!itemsEl.value?.contains(window.document.activeElement)) return;
const focusableElements = Array.from(itemsEl.value.children).filter(isFocusable); const focusableElements = Array.from(itemsEl.value.children).filter(isFocusable);
const activeIndex = focusableElements.findIndex(el => el === document.activeElement); const activeIndex = focusableElements.findIndex(el => el === window.document.activeElement);
const targetIndex = (activeIndex !== -1 && activeIndex !== (focusableElements.length - 1)) ? (activeIndex + 1) : 0; const targetIndex = (activeIndex !== -1 && activeIndex !== (focusableElements.length - 1)) ? (activeIndex + 1) : 0;
const targetElement = focusableElements.at(targetIndex) ?? itemsEl.value; const targetElement = focusableElements.at(targetIndex) ?? itemsEl.value;
@ -400,9 +400,9 @@ const onGlobalMousedown = (ev: MouseEvent) => {
const setupHandlers = () => { const setupHandlers = () => {
if (!isNestingMenu) { if (!isNestingMenu) {
document.addEventListener('focusin', onGlobalFocusin, { passive: true }); window.document.addEventListener('focusin', onGlobalFocusin, { passive: true });
} }
document.addEventListener('mousedown', onGlobalMousedown, { passive: true }); window.document.addEventListener('mousedown', onGlobalMousedown, { passive: true });
}; };
let disposed = false; let disposed = false;
@ -410,9 +410,9 @@ let disposed = false;
const disposeHandlers = () => { const disposeHandlers = () => {
disposed = true; disposed = true;
if (!isNestingMenu) { if (!isNestingMenu) {
document.removeEventListener('focusin', onGlobalFocusin); window.document.removeEventListener('focusin', onGlobalFocusin);
} }
document.removeEventListener('mousedown', onGlobalMousedown); window.document.removeEventListener('mousedown', onGlobalMousedown);
}; };
onMounted(() => { onMounted(() => {

View File

@ -48,7 +48,7 @@ const polygonPoints = ref('');
const headX = ref<number | null>(null); const headX = ref<number | null>(null);
const headY = ref<number | null>(null); const headY = ref<number | null>(null);
const clock = ref<number | null>(null); const clock = ref<number | null>(null);
const accent = tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--MI_THEME-accent')); const accent = tinycolor(getComputedStyle(window.document.documentElement).getPropertyValue('--MI_THEME-accent'));
const color = accent.toRgbString(); const color = accent.toRgbString();
function draw(): void { function draw(): void {

View File

@ -59,7 +59,7 @@ const pagination = computed(() => prefer.r.useGroupedNotifications.value ? {
function onNotification(notification) { function onNotification(notification) {
const isMuted = props.excludeTypes ? props.excludeTypes.includes(notification.type) : false; const isMuted = props.excludeTypes ? props.excludeTypes.includes(notification.type) : false;
if (isMuted || document.visibilityState === 'visible') { if (isMuted || window.document.visibilityState === 'visible') {
useStream().send('readNotification'); useStream().send('readNotification');
} }

View File

@ -142,7 +142,7 @@ const {
} = prefer.r; } = prefer.r;
const contentEl = computed(() => props.pagination.pageEl ?? rootEl.value); const contentEl = computed(() => props.pagination.pageEl ?? rootEl.value);
const scrollableElement = computed(() => contentEl.value ? getScrollContainer(contentEl.value) : document.body); const scrollableElement = computed(() => contentEl.value ? getScrollContainer(contentEl.value) : window.document.body);
const visibility = useDocumentVisibility(); const visibility = useDocumentVisibility();

View File

@ -151,9 +151,9 @@ function onMousedown(ev: MouseEvent | TouchEvent) {
closed: () => dispose(), closed: () => dispose(),
}); });
const style = document.createElement('style'); const style = window.document.createElement('style');
style.appendChild(document.createTextNode('* { cursor: grabbing !important; } body * { pointer-events: none !important; }')); style.appendChild(window.document.createTextNode('* { cursor: grabbing !important; } body * { pointer-events: none !important; }'));
document.head.appendChild(style); window.document.head.appendChild(style);
const thumbWidth = getThumbWidth(); const thumbWidth = getThumbWidth();
@ -172,7 +172,7 @@ function onMousedown(ev: MouseEvent | TouchEvent) {
let beforeValue = finalValue.value; let beforeValue = finalValue.value;
const onMouseup = () => { const onMouseup = () => {
document.head.removeChild(style); window.document.head.removeChild(style);
tooltipForDragShowing.value = false; tooltipForDragShowing.value = false;
window.removeEventListener('mousemove', onDrag); window.removeEventListener('mousemove', onDrag);
window.removeEventListener('touchmove', onDrag); window.removeEventListener('touchmove', onDrag);

View File

@ -136,7 +136,7 @@ async function menu(ev) {
} }
function anime() { function anime() {
if (document.hidden || !prefer.s.animation || buttonEl.value == null) return; if (window.document.hidden || !prefer.s.animation || buttonEl.value == null) return;
const rect = buttonEl.value.getBoundingClientRect(); const rect = buttonEl.value.getBoundingClientRect();
const x = rect.left + 16; const x = rect.left + 16;

View File

@ -44,7 +44,7 @@ onMounted(async () => {
const vLineColor = store.s.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)'; const vLineColor = store.s.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
const accent = tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--MI_THEME-accent')); const accent = tinycolor(getComputedStyle(window.document.documentElement).getPropertyValue('--MI_THEME-accent'));
const color = accent.toHex(); const color = accent.toHex();
if (chartEl.value == null) return; if (chartEl.value == null) return;

View File

@ -267,7 +267,7 @@ async function onSubmit(): Promise<void> {
'testcaptcha-response': testcaptchaResponse.value, 'testcaptcha-response': testcaptchaResponse.value,
}; };
const res = await fetch(`${config.apiUrl}/signup`, { const res = await window.fetch(`${config.apiUrl}/signup`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',

View File

@ -20,7 +20,7 @@ import tinycolor from 'tinycolor2';
const loaded = !!window.TagCanvas; const loaded = !!window.TagCanvas;
const SAFE_FOR_HTML_ID = 'abcdefghijklmnopqrstuvwxyz'; const SAFE_FOR_HTML_ID = 'abcdefghijklmnopqrstuvwxyz';
const computedStyle = getComputedStyle(document.documentElement); const computedStyle = getComputedStyle(window.document.documentElement);
const idForCanvas = Array.from({ length: 16 }, () => SAFE_FOR_HTML_ID[Math.floor(Math.random() * SAFE_FOR_HTML_ID.length)]).join(''); const idForCanvas = Array.from({ length: 16 }, () => SAFE_FOR_HTML_ID[Math.floor(Math.random() * SAFE_FOR_HTML_ID.length)]).join('');
const idForTags = Array.from({ length: 16 }, () => SAFE_FOR_HTML_ID[Math.floor(Math.random() * SAFE_FOR_HTML_ID.length)]).join(''); const idForTags = Array.from({ length: 16 }, () => SAFE_FOR_HTML_ID[Math.floor(Math.random() * SAFE_FOR_HTML_ID.length)]).join('');
const available = ref(false); const available = ref(false);
@ -57,7 +57,7 @@ onMounted(() => {
if (loaded) { if (loaded) {
available.value = true; available.value = true;
} else { } else {
document.head.appendChild(Object.assign(document.createElement('script'), { window.document.head.appendChild(Object.assign(window.document.createElement('script'), {
async: true, async: true,
src: '/client-assets/tagcanvas.min.js', src: '/client-assets/tagcanvas.min.js',
})).addEventListener('load', () => available.value = true); })).addEventListener('load', () => available.value = true);

View File

@ -61,7 +61,7 @@ async function renderChart() {
const vLineColor = store.s.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)'; const vLineColor = store.s.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
const computedStyle = getComputedStyle(document.documentElement); const computedStyle = getComputedStyle(window.document.documentElement);
const accent = tinycolor(computedStyle.getPropertyValue('--MI_THEME-accent')).toHexString(); const accent = tinycolor(computedStyle.getPropertyValue('--MI_THEME-accent')).toHexString();
const colorRead = accent; const colorRead = accent;

View File

@ -240,7 +240,7 @@ function onHeaderMousedown(evt: MouseEvent | TouchEvent) {
const main = rootEl.value; const main = rootEl.value;
if (main == null) return; if (main == null) return;
if (!contains(main, document.activeElement)) main.focus(); if (!contains(main, window.document.activeElement)) main.focus();
const position = main.getBoundingClientRect(); const position = main.getBoundingClientRect();

View File

@ -87,7 +87,7 @@ function openWindow() {
function nav(ev: MouseEvent) { function nav(ev: MouseEvent) {
if (behavior === 'browser') { if (behavior === 'browser') {
location.href = props.to; window.location.href = props.to;
return; return;
} }

View File

@ -170,7 +170,7 @@ onMounted(() => {
if (props.rootEl) { if (props.rootEl) {
ro2 = new ResizeObserver((entries, observer) => { ro2 = new ResizeObserver((entries, observer) => {
if (document.body.contains(el.value as HTMLElement)) { if (window.document.body.contains(el.value as HTMLElement)) {
nextTick(() => renderTab()); nextTick(() => renderTab());
} }
}); });

View File

@ -69,6 +69,8 @@ const emit = defineEmits<{
(ev: 'update:tab', key: string); (ev: 'update:tab', key: string);
}>(); }>();
const viewId = inject(DI.viewId);
const viewTransitionName = computed(() => `${viewId}---pageHeader`);
const injectedPageMetadata = inject(DI.pageMetadata); const injectedPageMetadata = inject(DI.pageMetadata);
const pageMetadata = computed(() => props.overridePageMetadata ?? injectedPageMetadata.value); const pageMetadata = computed(() => props.overridePageMetadata ?? injectedPageMetadata.value);
@ -106,7 +108,7 @@ function onTabClick(): void {
const calcBg = () => { const calcBg = () => {
const rawBg = 'var(--MI_THEME-bg)'; const rawBg = 'var(--MI_THEME-bg)';
const tinyBg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg); const tinyBg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(window.document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg);
tinyBg.setAlpha(0.85); tinyBg.setAlpha(0.85);
bg.value = tinyBg.toRgbString(); bg.value = tinyBg.toRgbString();
}; };
@ -120,7 +122,7 @@ onMounted(() => {
if (el.value && el.value.parentElement) { if (el.value && el.value.parentElement) {
narrow.value = el.value.parentElement.offsetWidth < 500; narrow.value = el.value.parentElement.offsetWidth < 500;
ro = new ResizeObserver((entries, observer) => { ro = new ResizeObserver((entries, observer) => {
if (el.value && el.value.parentElement && document.body.contains(el.value as HTMLElement)) { if (el.value && el.value.parentElement && window.document.body.contains(el.value as HTMLElement)) {
narrow.value = el.value.parentElement.offsetWidth < 500; narrow.value = el.value.parentElement.offsetWidth < 500;
} }
}); });
@ -140,6 +142,7 @@ onUnmounted(() => {
backdrop-filter: var(--MI-blur, blur(15px)); backdrop-filter: var(--MI-blur, blur(15px));
border-bottom: solid 0.5px var(--MI_THEME-divider); border-bottom: solid 0.5px var(--MI_THEME-divider);
width: 100%; width: 100%;
view-transition-name: v-bind(viewTransitionName);
} }
.upper, .upper,

View File

@ -0,0 +1,32 @@
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<MkStickyContainer class="_pageScrollable">
<template #header><MkPageHeader v-model:tab="tab" :actions="actions" :tabs="tabs"/></template>
<slot></slot>
</MkStickyContainer>
</template>
<script lang="ts" setup>
import type { PageHeaderItem } from '@/types/page-header.js';
import type { Tab } from './MkPageHeader.tabs.vue';
const props = withDefaults(defineProps<{
tabs?: Tab[];
actions?: PageHeaderItem[] | null;
thin?: boolean;
hideTitle?: boolean;
displayMyAvatar?: boolean;
}>(), {
tabs: () => ([] as Tab[]),
});
const tab = defineModel<string>('tab');
</script>
<style lang="scss" module>
</style>

View File

@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<div class="_pageContainer" style="height: 100%;"> <div ref="rootEl" class="_pageContainer" :class="$style.root">
<KeepAlive :max="prefer.s.numberOfPageCache"> <KeepAlive :max="prefer.s.numberOfPageCache">
<Suspense :timeout="0"> <Suspense :timeout="0">
<component :is="currentPageComponent" :key="key" v-bind="Object.fromEntries(currentPageProps)"/> <component :is="currentPageComponent" :key="key" v-bind="Object.fromEntries(currentPageProps)"/>
@ -18,11 +18,13 @@ SPDX-License-Identifier: AGPL-3.0-only
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { inject, provide, ref, shallowRef } from 'vue'; import { inject, nextTick, onMounted, provide, ref, shallowRef, useTemplateRef } from 'vue';
import type { Router } from '@/router.js'; import type { Router } from '@/router.js';
import { prefer } from '@/preferences.js'; import { prefer } from '@/preferences.js';
import MkLoadingPage from '@/pages/_loading_.vue'; import MkLoadingPage from '@/pages/_loading_.vue';
import { DI } from '@/di.js'; import { DI } from '@/di.js';
import { randomId } from '@/utility/random-id.js';
import { deepEqual } from '@/utility/deep-equal.js';
const props = defineProps<{ const props = defineProps<{
router?: Router; router?: Router;
@ -34,18 +36,76 @@ if (router == null) {
throw new Error('no router provided'); throw new Error('no router provided');
} }
const viewId = randomId();
provide(DI.viewId, viewId);
const currentDepth = inject(DI.routerCurrentDepth, 0); const currentDepth = inject(DI.routerCurrentDepth, 0);
provide(DI.routerCurrentDepth, currentDepth + 1); provide(DI.routerCurrentDepth, currentDepth + 1);
const rootEl = useTemplateRef('rootEl');
onMounted(() => {
rootEl.value.style.viewTransitionName = viewId; // view-transition-namecss 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>

View File

@ -42,7 +42,7 @@ const highlighted = ref(props.markerId === searchMarkerId.value);
function checkChildren() { function checkChildren() {
if (props.children?.includes(searchMarkerId.value)) { if (props.children?.includes(searchMarkerId.value)) {
const el = document.querySelector(`[data-in-app-search-marker-id="${searchMarkerId.value}"]`); const el = window.document.querySelector(`[data-in-app-search-marker-id="${searchMarkerId.value}"]`);
highlighted.value = el == null; highlighted.value = el == null;
} }
} }

View File

@ -25,6 +25,8 @@ import MkPageHeader from './global/MkPageHeader.vue';
import MkSpacer from './global/MkSpacer.vue'; import MkSpacer from './global/MkSpacer.vue';
import MkStickyContainer from './global/MkStickyContainer.vue'; import MkStickyContainer from './global/MkStickyContainer.vue';
import MkLazy from './global/MkLazy.vue'; import MkLazy from './global/MkLazy.vue';
import PageWithHeader from './global/PageWithHeader.vue';
import PageWithAnimBg from './global/PageWithAnimBg.vue';
import SearchMarker from './global/SearchMarker.vue'; import SearchMarker from './global/SearchMarker.vue';
import SearchLabel from './global/SearchLabel.vue'; import SearchLabel from './global/SearchLabel.vue';
import SearchKeyword from './global/SearchKeyword.vue'; import SearchKeyword from './global/SearchKeyword.vue';
@ -60,6 +62,8 @@ export const components = {
MkSpacer: MkSpacer, MkSpacer: MkSpacer,
MkStickyContainer: MkStickyContainer, MkStickyContainer: MkStickyContainer,
MkLazy: MkLazy, MkLazy: MkLazy,
PageWithHeader: PageWithHeader,
PageWithAnimBg: PageWithAnimBg,
SearchMarker: SearchMarker, SearchMarker: SearchMarker,
SearchLabel: SearchLabel, SearchLabel: SearchLabel,
SearchKeyword: SearchKeyword, SearchKeyword: SearchKeyword,
@ -89,6 +93,8 @@ declare module '@vue/runtime-core' {
MkSpacer: typeof MkSpacer; MkSpacer: typeof MkSpacer;
MkStickyContainer: typeof MkStickyContainer; MkStickyContainer: typeof MkStickyContainer;
MkLazy: typeof MkLazy; MkLazy: typeof MkLazy;
PageWithHeader: typeof PageWithHeader;
PageWithAnimBg: typeof PageWithAnimBg;
SearchMarker: typeof SearchMarker; SearchMarker: typeof SearchMarker;
SearchLabel: typeof SearchLabel; SearchLabel: typeof SearchLabel;
SearchKeyword: typeof SearchKeyword; SearchKeyword: typeof SearchKeyword;

View File

@ -11,4 +11,5 @@ 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>,
}; };

View File

@ -13,7 +13,7 @@ export default {
el._keyHandler = makeHotkey(binding.value); el._keyHandler = makeHotkey(binding.value);
if (el._hotkey_global) { if (el._hotkey_global) {
document.addEventListener('keydown', el._keyHandler, { passive: false }); window.document.addEventListener('keydown', el._keyHandler, { passive: false });
} else { } else {
el.addEventListener('keydown', el._keyHandler, { passive: false }); el.addEventListener('keydown', el._keyHandler, { passive: false });
} }
@ -21,7 +21,7 @@ export default {
unmounted(el) { unmounted(el) {
if (el._hotkey_global) { if (el._hotkey_global) {
document.removeEventListener('keydown', el._keyHandler); window.document.removeEventListener('keydown', el._keyHandler);
} else { } else {
el.removeEventListener('keydown', el._keyHandler); el.removeEventListener('keydown', el._keyHandler);
} }

View File

@ -10,7 +10,7 @@ export default {
mounted(src, binding, vn) { mounted(src, binding, vn) {
const parentBg = getBgColor(src.parentElement) ?? 'transparent'; const parentBg = getBgColor(src.parentElement) ?? 'transparent';
const myBg = getComputedStyle(document.documentElement).getPropertyValue('--MI_THEME-panel'); const myBg = getComputedStyle(window.document.documentElement).getPropertyValue('--MI_THEME-panel');
if (parentBg === myBg) { if (parentBg === myBg) {
src.style.backgroundColor = 'var(--MI_THEME-bg)'; src.style.backgroundColor = 'var(--MI_THEME-bg)';

View File

@ -47,7 +47,7 @@ export default {
} }
self.show = () => { self.show = () => {
if (!document.body.contains(el)) return; if (!window.document.body.contains(el)) return;
if (self._close) return; if (self._close) return;
if (self.text == null) return; if (self.text == null) return;

View File

@ -31,7 +31,7 @@ export class UserPreview {
} }
private show() { private show() {
if (!document.body.contains(this.el)) return; if (!window.document.body.contains(this.el)) return;
if (this.promise) return; if (this.promise) return;
const showing = ref(true); const showing = ref(true);
@ -58,7 +58,7 @@ export class UserPreview {
}; };
this.checkTimer = window.setInterval(() => { this.checkTimer = window.setInterval(() => {
if (!document.body.contains(this.el)) { if (!window.document.body.contains(this.el)) {
window.clearTimeout(this.showTimer); window.clearTimeout(this.showTimer);
window.clearTimeout(this.hideTimer); window.clearTimeout(this.hideTimer);
this.close(); this.close();

View File

@ -12,7 +12,7 @@ import { DEFAULT_INFO_IMAGE_URL, DEFAULT_NOT_FOUND_IMAGE_URL, DEFAULT_SERVER_ERR
// TODO: 他のタブと永続化されたstateを同期 // TODO: 他のタブと永続化されたstateを同期
//#region loader //#region loader
const providedMetaEl = document.getElementById('misskey_meta'); const providedMetaEl = window.document.getElementById('misskey_meta');
let cachedMeta = miLocalStorage.getItem('instance') ? JSON.parse(miLocalStorage.getItem('instance')!) : null; let cachedMeta = miLocalStorage.getItem('instance') ? JSON.parse(miLocalStorage.getItem('instance')!) : null;
let cachedAt = miLocalStorage.getItem('instanceCachedAt') ? parseInt(miLocalStorage.getItem('instanceCachedAt')!) : 0; let cachedAt = miLocalStorage.getItem('instanceCachedAt') ? parseInt(miLocalStorage.getItem('instanceCachedAt')!) : 0;

View File

@ -320,7 +320,7 @@ export class Nirax<DEF extends RouteDef[]> extends EventEmitter<RouterEvents> {
} }
const res = this.navigate(fullPath); const res = this.navigate(fullPath);
if (res.route.path === '/:(*)') { if (res.route.path === '/:(*)') {
location.href = fullPath; window.location.href = fullPath;
} else { } else {
this.emit('push', { this.emit('push', {
beforeFullPath, beforeFullPath,

View File

@ -167,7 +167,7 @@ export const navbarItemDef = reactive({
title: i18n.ts.reload, title: i18n.ts.reload,
icon: 'ti ti-refresh', icon: 'ti ti-refresh',
action: (ev) => { action: (ev) => {
location.reload(); window.location.reload();
}, },
}, },
profile: { profile: {

View File

@ -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';
@ -185,7 +185,7 @@ export function popup<
>( >(
component: T, component: T,
props: ComponentProps<T>, props: ComponentProps<T>,
events: ComponentEmit<T> = {} as ComponentEmit<T>, events: Partial<ComponentEmit<T>> = {},
): { ): {
dispose: () => void; dispose: () => void;
componentRef: ShallowRef<TI | null>; componentRef: ShallowRef<TI | null>;
@ -471,7 +471,7 @@ export function authenticateDialog(): Promise<{
canceled: false; result: { password: string; token: string | null; }; canceled: false; result: { password: string; token: string | null; };
}> { }> {
return new Promise(resolve => { return new Promise(resolve => {
const { dispose } = popup(MkPasswordDialog, {}, { const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkPasswordDialog.vue')), {}, {
done: result => { done: result => {
resolve(result ? { canceled: false, result } : { canceled: true, result: undefined }); resolve(result ? { canceled: false, result } : { canceled: true, result: undefined });
}, },
@ -628,12 +628,7 @@ export async function selectDriveFolder(multiple: boolean): Promise<Misskey.enti
}); });
} }
export async function selectRole(params: { export async function selectRole(params: ComponentProps<typeof MkRoleSelectDialog_TypeReferenceOnly>): Promise<
initialRoleIds?: string[],
title?: string,
infoMessage?: string,
publicOnly?: boolean,
}): Promise<
{ canceled: true; result: undefined; } | { canceled: true; result: undefined; } |
{ canceled: false; result: Misskey.entities.Role[] } { canceled: false; result: Misskey.entities.Role[] }
> { > {
@ -645,16 +640,14 @@ export async function selectRole(params: {
close: () => { close: () => {
resolve({ canceled: true, result: undefined }); resolve({ canceled: true, result: undefined });
}, },
closed: () => { closed: () => dispose(),
dispose();
},
}); });
}); });
} }
export async function pickEmoji(src: HTMLElement, opts: ComponentProps<typeof MkEmojiPickerDialog>): Promise<string> { export async function pickEmoji(src: HTMLElement, opts: ComponentProps<typeof MkEmojiPickerDialog_TypeReferenceOnly>): Promise<string> {
return new Promise(resolve => { return new Promise(resolve => {
const { dispose } = popup(MkEmojiPickerDialog, { const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkEmojiPickerDialog.vue')), {
src, src,
...opts, ...opts,
}, { }, {
@ -689,7 +682,11 @@ export function popupMenu(items: MenuItem[], src?: HTMLElement | EventTarget | n
width?: number; width?: number;
onClosing?: () => void; onClosing?: () => void;
}): Promise<void> { }): Promise<void> {
let returnFocusTo = getHTMLElementOrNull(src) ?? getHTMLElementOrNull(document.activeElement); if (!(src instanceof HTMLElement)) {
src = null;
}
let returnFocusTo = getHTMLElementOrNull(src) ?? getHTMLElementOrNull(window.document.activeElement);
return new Promise(resolve => nextTick(() => { return new Promise(resolve => nextTick(() => {
const { dispose } = popup(MkPopupMenu, { const { dispose } = popup(MkPopupMenu, {
items, items,
@ -718,7 +715,7 @@ export function contextMenu(items: MenuItem[], ev: MouseEvent): Promise<void> {
return Promise.resolve(); return Promise.resolve();
} }
let returnFocusTo = getHTMLElementOrNull(ev.currentTarget ?? ev.target) ?? getHTMLElementOrNull(document.activeElement); let returnFocusTo = getHTMLElementOrNull(ev.currentTarget ?? ev.target) ?? getHTMLElementOrNull(window.document.activeElement);
ev.preventDefault(); ev.preventDefault();
return new Promise(resolve => nextTick(() => { return new Promise(resolve => nextTick(() => {
const { dispose } = popup(MkContextMenu, { const { dispose } = popup(MkContextMenu, {

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<div style="overflow: clip;"> <div style="overflow: clip;">
<MkSpacer :contentMax="600" :marginMin="20"> <MkSpacer :contentMax="600" :marginMin="20">
<div class="_gaps_m znqjceqz"> <div class="_gaps_m znqjceqz">
@ -130,7 +129,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</MkSpacer> </MkSpacer>
</div> </div>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
<MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs"> <MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs">
<MkSpacer v-if="tab === 'overview'" :contentMax="600" :marginMin="20"> <MkSpacer v-if="tab === 'overview'" :contentMax="600" :marginMin="20">
<XOverview/> <XOverview/>
@ -20,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkInstanceStats/> <MkInstanceStats/>
</MkSpacer> </MkSpacer>
</MkHorizontalSwipe> </MkHorizontalSwipe>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,12 +4,11 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader>
<template #header><MkPageHeader/></template>
<MkSpacer :contentMax="1200"> <MkSpacer :contentMax="1200">
<MkAchievements :user="$i"/> <MkAchievements :user="$i"/>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer v-if="file" :contentMax="600" :marginMin="16" :marginMax="32"> <MkSpacer v-if="file" :contentMax="600" :marginMin="16" :marginMax="32">
<div v-if="tab === 'overview'" class="cxqhhsmd _gaps_m"> <div v-if="tab === 'overview'" class="cxqhhsmd _gaps_m">
<a class="thumbnail" :href="file.url" target="_blank"> <a class="thumbnail" :href="file.url" target="_blank">
@ -67,7 +66,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkObjectView> </MkObjectView>
</div> </div>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="600" :marginMin="16" :marginMax="32"> <MkSpacer :contentMax="600" :marginMin="16" :marginMax="32">
<FormSuspense :p="init"> <FormSuspense :p="init">
<div v-if="tab === 'overview'" class="_gaps_m"> <div v-if="tab === 'overview'" class="_gaps_m">
@ -208,7 +207,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</FormSuspense> </FormSuspense>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -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(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg); const tinyBg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(window.document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg);
tinyBg.setAlpha(0.85); tinyBg.setAlpha(0.85);
bg.value = tinyBg.toRgbString(); bg.value = tinyBg.toRgbString();
}; };

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="800" :marginMin="16" :marginMax="32"> <MkSpacer :contentMax="800" :marginMin="16" :marginMax="32">
<FormSuspense v-slot="{ result: database }" :p="databasePromiseFactory"> <FormSuspense v-slot="{ result: database }" :p="databasePromiseFactory">
<MkKeyValue v-for="table in database" :key="table[0]" oneline style="margin: 1em 0;"> <MkKeyValue v-for="table in database" :key="table[0]" oneline style="margin: 1em 0;">
@ -14,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkKeyValue> </MkKeyValue>
</FormSuspense> </FormSuspense>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -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(document.documentElement).getPropertyValue('--MI_THEME-panel'), borderColor: getComputedStyle(window.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),

View File

@ -4,15 +4,13 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader>
<template #header><MkPageHeader/></template>
<MkSpacer :contentMax="500"> <MkSpacer :contentMax="500">
<div class="_gaps"> <div class="_gaps">
<MkAd v-for="ad in instance.ads" :key="ad.id" :specify="ad"/> <MkAd v-for="ad in instance.ads" :key="ad.id" :specify="ad"/>
</div> </div>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="800"> <MkSpacer :contentMax="800">
<Transition <Transition
:enterActiveClass="prefer.s.animation ? $style.fadeEnterActive : ''" :enterActiveClass="prefer.s.animation ? $style.fadeEnterActive : ''"
@ -44,7 +43,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkLoading v-else/> <MkLoading v-else/>
</Transition> </Transition>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,11 +4,10 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="800"> <MkSpacer :contentMax="800">
<MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs"> <MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs">
<div :key="tab" class="_gaps"> <div class="_gaps">
<MkInfo v-if="$i && $i.hasUnreadAnnouncement && tab === 'current'" warn>{{ i18n.ts.youHaveUnreadAnnouncements }}</MkInfo> <MkInfo v-if="$i && $i.hasUnreadAnnouncement && tab === 'current'" warn>{{ i18n.ts.youHaveUnreadAnnouncements }}</MkInfo>
<MkPagination ref="paginationEl" :key="tab" v-slot="{items}" :pagination="tab === 'current' ? paginationCurrent : paginationPast" class="_gaps"> <MkPagination ref="paginationEl" :key="tab" v-slot="{items}" :pagination="tab === 'current' ? paginationCurrent : paginationPast" class="_gaps">
<section v-for="announcement in items" :key="announcement.id" class="_panel" :class="$style.announcement"> <section v-for="announcement in items" :key="announcement.id" class="_panel" :class="$style.announcement">
@ -43,7 +42,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</MkHorizontalSwipe> </MkHorizontalSwipe>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="800"> <MkSpacer :contentMax="800">
<div ref="rootEl"> <div ref="rootEl">
<div v-if="queue > 0" :class="$style.new"><button class="_buttonPrimary" :class="$style.newButton" @click="top()">{{ i18n.ts.newNoteRecived }}</button></div> <div v-if="queue > 0" :class="$style.new"><button class="_buttonPrimary" :class="$style.newButton" @click="top()">{{ i18n.ts.newNoteRecived }}</button></div>
@ -20,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</div> </div>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="700"> <MkSpacer :contentMax="700">
<div class="_gaps_m"> <div class="_gaps_m">
<div class="_gaps_m"> <div class="_gaps_m">
@ -30,7 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</div> </div>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -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 = document.createElement('div'); const el = window.document.createElement('div');
el.textContent = app.value.name; el.textContent = app.value.name;
return el.innerHTML; return el.innerHTML;
}); });

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="500"> <MkSpacer :contentMax="500">
<div v-if="state == 'fetch-session-error'"> <div v-if="state == 'fetch-session-error'">
<p>{{ i18n.ts.somethingHappened }}</p> <p>{{ i18n.ts.somethingHappened }}</p>
@ -38,7 +37,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkSignin @login="onLogin"/> <MkSignin @login="onLogin"/>
</div> </div>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -64,7 +63,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');
location.href = `${session.value.app.callbackUrl}?token=${session.value.token}`; window.location.href = `${session.value.app.callbackUrl}?token=${session.value.token}`;
} }
} }

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="900"> <MkSpacer :contentMax="900">
<div class="_gaps"> <div class="_gaps">
<div :class="$style.decorations"> <div :class="$style.decorations">
@ -22,7 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</div> </div>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="700"> <MkSpacer :contentMax="700">
<div v-if="channelId == null || channel != null" class="_gaps_m"> <div v-if="channelId == null || channel != null" class="_gaps_m">
<MkInput v-model="name"> <MkInput v-model="name">
@ -65,7 +64,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</div> </div>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,11 +4,10 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="700" :class="$style.main"> <MkSpacer :contentMax="700" :class="$style.main">
<MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs"> <MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs">
<div v-if="channel && tab === 'overview'" key="overview" class="_gaps"> <div v-if="channel && tab === 'overview'" class="_gaps">
<div class="_panel" :class="$style.bannerContainer"> <div class="_panel" :class="$style.bannerContainer">
<XChannelFollowButton :channel="channel" :full="true" :class="$style.subscribe"/> <XChannelFollowButton :channel="channel" :full="true" :class="$style.subscribe"/>
<MkButton v-if="favorited" v-tooltip="i18n.ts.unfavorite" asLike class="button" rounded primary :class="$style.favorite" @click="unfavorite()"><i class="ti ti-star"></i></MkButton> <MkButton v-if="favorited" v-tooltip="i18n.ts.unfavorite" asLike class="button" rounded primary :class="$style.favorite" @click="unfavorite()"><i class="ti ti-star"></i></MkButton>
@ -33,7 +32,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</MkFoldableSection> </MkFoldableSection>
</div> </div>
<div v-if="channel && tab === 'timeline'" key="timeline" class="_gaps"> <div v-if="channel && tab === 'timeline'" class="_gaps">
<MkInfo v-if="channel.isArchived" warn>{{ i18n.ts.thisChannelArchived }}</MkInfo> <MkInfo v-if="channel.isArchived" warn>{{ i18n.ts.thisChannelArchived }}</MkInfo>
<!-- スマホタブレットの場合キーボードが表示されると投稿が見づらくなるのでデスクトップ場合のみ自動でフォーカスを当てる --> <!-- スマホタブレットの場合キーボードが表示されると投稿が見づらくなるのでデスクトップ場合のみ自動でフォーカスを当てる -->
@ -41,10 +40,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkTimeline :key="channelId" src="channel" :channel="channelId" @before="before" @after="after" @note="miLocalStorage.setItemAsJson(`channelLastReadedAt:${channel.id}`, Date.now())"/> <MkTimeline :key="channelId" src="channel" :channel="channelId" @before="before" @after="after" @note="miLocalStorage.setItemAsJson(`channelLastReadedAt:${channel.id}`, Date.now())"/>
</div> </div>
<div v-else-if="tab === 'featured'" key="featured"> <div v-else-if="tab === 'featured'">
<MkNotes :pagination="featuredPagination"/> <MkNotes :pagination="featuredPagination"/>
</div> </div>
<div v-else-if="tab === 'search'" key="search"> <div v-else-if="tab === 'search'">
<div v-if="notesSearchAvailable" class="_gaps"> <div v-if="notesSearchAvailable" class="_gaps">
<div> <div>
<MkInput v-model="searchQuery" @enter="search()"> <MkInput v-model="searchQuery" @enter="search()">
@ -69,7 +68,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkSpacer> </MkSpacer>
</div> </div>
</template> </template>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,11 +4,10 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="1200"> <MkSpacer :contentMax="1200">
<MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs"> <MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs">
<div v-if="tab === 'search'" key="search" :class="$style.searchRoot"> <div v-if="tab === 'search'" :class="$style.searchRoot">
<div class="_gaps"> <div class="_gaps">
<MkInput v-model="searchQuery" :large="true" :autofocus="true" type="search" @enter="search"> <MkInput v-model="searchQuery" :large="true" :autofocus="true" type="search" @enter="search">
<template #prefix><i class="ti ti-search"></i></template> <template #prefix><i class="ti ti-search"></i></template>
@ -25,28 +24,28 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkChannelList :key="key" :pagination="channelPagination"/> <MkChannelList :key="key" :pagination="channelPagination"/>
</MkFoldableSection> </MkFoldableSection>
</div> </div>
<div v-if="tab === 'featured'" key="featured"> <div v-if="tab === 'featured'">
<MkPagination v-slot="{items}" :pagination="featuredPagination"> <MkPagination v-slot="{items}" :pagination="featuredPagination">
<div :class="$style.root"> <div :class="$style.root">
<MkChannelPreview v-for="channel in items" :key="channel.id" :channel="channel"/> <MkChannelPreview v-for="channel in items" :key="channel.id" :channel="channel"/>
</div> </div>
</MkPagination> </MkPagination>
</div> </div>
<div v-else-if="tab === 'favorites'" key="favorites"> <div v-else-if="tab === 'favorites'">
<MkPagination v-slot="{items}" :pagination="favoritesPagination"> <MkPagination v-slot="{items}" :pagination="favoritesPagination">
<div :class="$style.root"> <div :class="$style.root">
<MkChannelPreview v-for="channel in items" :key="channel.id" :channel="channel"/> <MkChannelPreview v-for="channel in items" :key="channel.id" :channel="channel"/>
</div> </div>
</MkPagination> </MkPagination>
</div> </div>
<div v-else-if="tab === 'following'" key="following"> <div v-else-if="tab === 'following'">
<MkPagination v-slot="{items}" :pagination="followingPagination"> <MkPagination v-slot="{items}" :pagination="followingPagination">
<div :class="$style.root"> <div :class="$style.root">
<MkChannelPreview v-for="channel in items" :key="channel.id" :channel="channel"/> <MkChannelPreview v-for="channel in items" :key="channel.id" :channel="channel"/>
</div> </div>
</MkPagination> </MkPagination>
</div> </div>
<div v-else-if="tab === 'owned'" key="owned"> <div v-else-if="tab === 'owned'">
<MkButton class="new" @click="create()"><i class="ti ti-plus"></i></MkButton> <MkButton class="new" @click="create()"><i class="ti ti-plus"></i></MkButton>
<MkPagination v-slot="{items}" :pagination="ownedPagination"> <MkPagination v-slot="{items}" :pagination="ownedPagination">
<div :class="$style.root"> <div :class="$style.root">
@ -56,7 +55,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</MkHorizontalSwipe> </MkHorizontalSwipe>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,12 +4,11 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader>
<template #header><MkPageHeader/></template>
<MkSpacer :contentMax="800"> <MkSpacer :contentMax="800">
<MkClickerGame/> <MkClickerGame/>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader :actions="headerActions">
<template #header><MkPageHeader :actions="headerActions"/></template>
<MkSpacer :contentMax="800"> <MkSpacer :contentMax="800">
<div v-if="clip" class="_gaps"> <div v-if="clip" class="_gaps">
<div class="_panel"> <div class="_panel">
@ -27,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkNotes :pagination="pagination" :detail="true"/> <MkNotes :pagination="pagination" :detail="true"/>
</div> </div>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader>
<template #header><MkPageHeader/></template>
<MkSpacer :contentMax="600" :marginMin="20"> <MkSpacer :contentMax="600" :marginMin="20">
<div class="_gaps_m"> <div class="_gaps_m">
<MkKeyValue :copy="instance.maintainerName"> <MkKeyValue :copy="instance.maintainerName">
@ -31,7 +30,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkKeyValue> </MkKeyValue>
</div> </div>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="900"> <MkSpacer :contentMax="900">
<div class="ogwlenmc"> <div class="ogwlenmc">
<div v-if="tab === 'local'" class="local"> <div v-if="tab === 'local'" class="local">
@ -68,7 +67,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</div> </div>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -10,11 +10,11 @@ SPDX-License-Identifier: AGPL-3.0-only
</template> </template>
<MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs"> <MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs">
<MkSpacer v-if="tab === 'info'" key="info" :contentMax="800"> <MkSpacer v-if="tab === 'info'" :contentMax="800">
<XFileInfo :fileId="fileId"/> <XFileInfo :fileId="fileId"/>
</MkSpacer> </MkSpacer>
<MkSpacer v-else-if="tab === 'notes'" key="notes" :contentMax="800"> <MkSpacer v-else-if="tab === 'notes'" :contentMax="800">
<XNotes :fileId="fileId"/> <XNotes :fileId="fileId"/>
</MkSpacer> </MkSpacer>
</MkHorizontalSwipe> </MkHorizontalSwipe>

View File

@ -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 fetch(mono.img); const res = await window.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 = document.createElement('canvas'); const dcanvas = window.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');

View File

@ -4,20 +4,19 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
<MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs"> <MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs">
<div v-if="tab === 'featured'" key="featured"> <div v-if="tab === 'featured'">
<XFeatured/> <XFeatured/>
</div> </div>
<div v-else-if="tab === 'users'" key="users"> <div v-else-if="tab === 'users'">
<XUsers/> <XUsers/>
</div> </div>
<div v-else-if="tab === 'roles'" key="roles"> <div v-else-if="tab === 'roles'">
<XRoles/> <XRoles/>
</div> </div>
</MkHorizontalSwipe> </MkHorizontalSwipe>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader>
<template #header><MkPageHeader/></template>
<MkSpacer :contentMax="800"> <MkSpacer :contentMax="800">
<MkPagination :pagination="pagination"> <MkPagination :pagination="pagination">
<template #empty> <template #empty>
@ -22,7 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template> </template>
</MkPagination> </MkPagination>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="700"> <MkSpacer :contentMax="700">
<div class="_gaps"> <div class="_gaps">
<MkInput v-model="title"> <MkInput v-model="title">
@ -37,7 +36,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkSpacer> </MkSpacer>
</div> </div>
</template> </template>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,11 +4,10 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="700"> <MkSpacer :contentMax="700">
<MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs"> <MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs">
<div v-if="tab === 'featured'" key="featured"> <div v-if="tab === 'featured'">
<MkPagination v-slot="{items}" :pagination="featuredFlashsPagination"> <MkPagination v-slot="{items}" :pagination="featuredFlashsPagination">
<div class="_gaps_s"> <div class="_gaps_s">
<MkFlashPreview v-for="flash in items" :key="flash.id" :flash="flash"/> <MkFlashPreview v-for="flash in items" :key="flash.id" :flash="flash"/>
@ -16,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkPagination> </MkPagination>
</div> </div>
<div v-else-if="tab === 'my'" key="my"> <div v-else-if="tab === 'my'">
<div class="_gaps"> <div class="_gaps">
<MkButton gradate rounded style="margin: 0 auto;" @click="create()"><i class="ti ti-plus"></i></MkButton> <MkButton gradate rounded style="margin: 0 auto;" @click="create()"><i class="ti ti-plus"></i></MkButton>
<MkPagination v-slot="{items}" :pagination="myFlashsPagination"> <MkPagination v-slot="{items}" :pagination="myFlashsPagination">
@ -27,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</div> </div>
<div v-else-if="tab === 'liked'" key="liked"> <div v-else-if="tab === 'liked'">
<MkPagination v-slot="{items}" :pagination="likedFlashsPagination"> <MkPagination v-slot="{items}" :pagination="likedFlashsPagination">
<div class="_gaps_s"> <div class="_gaps_s">
<MkFlashPreview v-for="like in items" :key="like.flash.id" :flash="like.flash"/> <MkFlashPreview v-for="like in items" :key="like.flash.id" :flash="like.flash"/>
@ -36,7 +35,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</MkHorizontalSwipe> </MkHorizontalSwipe>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="700"> <MkSpacer :contentMax="700">
<Transition :name="prefer.s.animation ? 'fade' : ''" mode="out-in"> <Transition :name="prefer.s.animation ? 'fade' : ''" mode="out-in">
<div v-if="flash" :key="flash.id"> <div v-if="flash" :key="flash.id">
@ -58,7 +57,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkLoading v-else/> <MkLoading v-else/>
</Transition> </Transition>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,11 +4,9 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="800"> <MkSpacer :contentMax="800">
<MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs"> <MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs">
<div :key="tab" class="_gaps">
<MkPagination ref="paginationComponent" :pagination="pagination"> <MkPagination ref="paginationComponent" :pagination="pagination">
<template #empty> <template #empty>
<div class="_fullinfo"> <div class="_fullinfo">
@ -37,10 +35,9 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</template> </template>
</MkPagination> </MkPagination>
</div>
</MkHorizontalSwipe> </MkHorizontalSwipe>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="800" :marginMin="16" :marginMax="32"> <MkSpacer :contentMax="800" :marginMin="16" :marginMax="32">
<FormSuspense :p="init" class="_gaps"> <FormSuspense :p="init" class="_gaps">
<MkInput v-model="title"> <MkInput v-model="title">
@ -34,7 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</FormSuspense> </FormSuspense>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,11 +4,10 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="1400"> <MkSpacer :contentMax="1400">
<MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs"> <MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs">
<div v-if="tab === 'explore'" key="explore"> <div v-if="tab === 'explore'">
<MkFoldableSection class="_margin"> <MkFoldableSection class="_margin">
<template #header><i class="ti ti-clock"></i>{{ i18n.ts.recentPosts }}</template> <template #header><i class="ti ti-clock"></i>{{ i18n.ts.recentPosts }}</template>
<MkPagination v-slot="{items}" :pagination="recentPostsPagination" :disableAutoLoad="true"> <MkPagination v-slot="{items}" :pagination="recentPostsPagination" :disableAutoLoad="true">
@ -26,14 +25,14 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkPagination> </MkPagination>
</MkFoldableSection> </MkFoldableSection>
</div> </div>
<div v-else-if="tab === 'liked'" key="liked"> <div v-else-if="tab === 'liked'">
<MkPagination v-slot="{items}" :pagination="likedPostsPagination"> <MkPagination v-slot="{items}" :pagination="likedPostsPagination">
<div :class="$style.items"> <div :class="$style.items">
<MkGalleryPostPreview v-for="like in items" :key="like.id" :post="like.post" class="post"/> <MkGalleryPostPreview v-for="like in items" :key="like.id" :post="like.post" class="post"/>
</div> </div>
</MkPagination> </MkPagination>
</div> </div>
<div v-else-if="tab === 'my'" key="my"> <div v-else-if="tab === 'my'">
<MkA to="/gallery/new" class="_link" style="margin: 16px;"><i class="ti ti-plus"></i> {{ i18n.ts.postToGallery }}</MkA> <MkA to="/gallery/new" class="_link" style="margin: 16px;"><i class="ti ti-plus"></i> {{ i18n.ts.postToGallery }}</MkA>
<MkPagination v-slot="{items}" :pagination="myPostsPagination"> <MkPagination v-slot="{items}" :pagination="myPostsPagination">
<div :class="$style.items"> <div :class="$style.items">
@ -43,7 +42,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</MkHorizontalSwipe> </MkHorizontalSwipe>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="1000" :marginMin="16" :marginMax="32"> <MkSpacer :contentMax="1000" :marginMin="16" :marginMax="32">
<div class="_root"> <div class="_root">
<Transition :name="prefer.s.animation ? 'fade' : ''" mode="out-in"> <Transition :name="prefer.s.animation ? 'fade' : ''" mode="out-in">
@ -59,7 +58,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</Transition> </Transition>
</div> </div>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader>
<template #header><MkPageHeader/></template>
<MkSpacer :contentMax="800"> <MkSpacer :contentMax="800">
<div class="_gaps"> <div class="_gaps">
<div class="_panel" :class="$style.link"> <div class="_panel" :class="$style.link">
@ -20,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</div> </div>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkPageWithAnimBg> <PageWithAnimBg>
<MkSpacer :contentMax="550" :marginMax="50"> <MkSpacer :contentMax="550" :marginMax="50">
<MkLoading v-if="uiPhase === 'fetching'"/> <MkLoading v-if="uiPhase === 'fetching'"/>
<MkExtensionInstaller v-else-if="uiPhase === 'confirm' && data" :extension="data" @confirm="install()" @cancel="close_()"> <MkExtensionInstaller v-else-if="uiPhase === 'confirm' && data" :extension="data" @confirm="install()" @cancel="close_()">
@ -37,7 +37,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</div> </div>
</MkSpacer> </MkSpacer>
</MkPageWithAnimBg> </PageWithAnimBg>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -57,7 +57,6 @@ import { parseThemeCode, installTheme } from '@/theme.js';
import { unisonReload } from '@/utility/unison-reload.js'; import { unisonReload } from '@/utility/unison-reload.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js'; import { definePage } from '@/page.js';
import MkPageWithAnimBg from '@/components/MkPageWithAnimBg.vue';
const uiPhase = ref<'fetching' | 'confirm' | 'error'>('fetching'); const uiPhase = ref<'fetching' | 'confirm' | 'error'>('fetching');
const errorKV = ref<{ const errorKV = ref<{

View File

@ -4,11 +4,10 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer v-if="instance" :contentMax="600" :marginMin="16" :marginMax="32"> <MkSpacer v-if="instance" :contentMax="600" :marginMin="16" :marginMax="32">
<MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs"> <MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs">
<div v-if="tab === 'overview'" key="overview" class="_gaps_m"> <div v-if="tab === 'overview'" class="_gaps_m">
<div class="fnfelxur"> <div class="fnfelxur">
<img :src="faviconUrl" alt="" class="icon"/> <img :src="faviconUrl" alt="" class="icon"/>
<span class="name">{{ instance.name || `(${i18n.ts.unknown})` }}</span> <span class="name">{{ instance.name || `(${i18n.ts.unknown})` }}</span>
@ -91,7 +90,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<FormLink :to="`https://${host}/manifest.json`" external style="margin-bottom: 8px;">manifest.json</FormLink> <FormLink :to="`https://${host}/manifest.json`" external style="margin-bottom: 8px;">manifest.json</FormLink>
</FormSection> </FormSection>
</div> </div>
<div v-else-if="tab === 'chart'" key="chart" class="_gaps_m"> <div v-else-if="tab === 'chart'" class="_gaps_m">
<div class="cmhjzshl"> <div class="cmhjzshl">
<div class="selects"> <div class="selects">
<MkSelect v-model="chartSrc" style="margin: 0 10px 0 0; flex: 1;"> <MkSelect v-model="chartSrc" style="margin: 0 10px 0 0; flex: 1;">
@ -116,27 +115,28 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</div> </div>
</div> </div>
<div v-else-if="tab === 'users'" key="users" class="_gaps_m"> <div v-else-if="tab === 'users'" class="_gaps_m">
<MkPagination v-slot="{items}" :pagination="usersPagination" style="display: grid; grid-template-columns: repeat(auto-fill,minmax(270px,1fr)); grid-gap: 12px;"> <MkPagination v-slot="{items}" :pagination="usersPagination" style="display: grid; grid-template-columns: repeat(auto-fill,minmax(270px,1fr)); grid-gap: 12px;">
<MkA v-for="user in items" :key="user.id" v-tooltip.mfm="`Last posted: ${dateString(user.updatedAt)}`" class="user" :to="`/admin/user/${user.id}`"> <MkA v-for="user in items" :key="user.id" v-tooltip.mfm="`Last posted: ${dateString(user.updatedAt)}`" class="user" :to="`/admin/user/${user.id}`">
<MkUserCardMini :user="user"/> <MkUserCardMini :user="user"/>
</MkA> </MkA>
</MkPagination> </MkPagination>
</div> </div>
<div v-else-if="tab === 'raw'" key="raw" class="_gaps_m"> <div v-else-if="tab === 'raw'" class="_gaps_m">
<MkObjectView tall :value="instance"> <MkObjectView tall :value="instance">
</MkObjectView> </MkObjectView>
</div> </div>
</MkHorizontalSwipe> </MkHorizontalSwipe>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed, watch } from 'vue'; import { ref, computed, watch } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import MkChart from '@/components/MkChart.vue';
import type { ChartSrc } from '@/components/MkChart.vue'; import type { ChartSrc } from '@/components/MkChart.vue';
import type { Paging } from '@/components/MkPagination.vue';
import MkChart from '@/components/MkChart.vue';
import MkObjectView from '@/components/MkObjectView.vue'; import MkObjectView from '@/components/MkObjectView.vue';
import FormLink from '@/components/form/link.vue'; import FormLink from '@/components/form/link.vue';
import MkLink from '@/components/MkLink.vue'; import MkLink from '@/components/MkLink.vue';
@ -153,7 +153,6 @@ import { definePage } from '@/page.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import MkUserCardMini from '@/components/MkUserCardMini.vue'; import MkUserCardMini from '@/components/MkUserCardMini.vue';
import MkPagination from '@/components/MkPagination.vue'; import MkPagination from '@/components/MkPagination.vue';
import type { Paging } from '@/components/MkPagination.vue';
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue'; import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
import { getProxiedImageUrlNullable } from '@/utility/media-proxy.js'; import { getProxiedImageUrlNullable } from '@/utility/media-proxy.js';
import { dateString } from '@/filters/date.js'; import { dateString } from '@/filters/date.js';

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader>
<template #header><MkPageHeader/></template>
<MkSpacer v-if="!instance.disableRegistration || !($i && ($i.isAdmin || $i.policies.canInvite))" :contentMax="1200"> <MkSpacer v-if="!instance.disableRegistration || !($i && ($i.isAdmin || $i.policies.canInvite))" :contentMax="1200">
<div :class="$style.root"> <div :class="$style.root">
<img :class="$style.img" :src="serverErrorImageUrl" draggable="false"/> <img :class="$style.img" :src="serverErrorImageUrl" draggable="false"/>
@ -30,7 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkPagination> </MkPagination>
</div> </div>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer v-if="error != null" :contentMax="1200"> <MkSpacer v-if="error != null" :contentMax="1200">
<div :class="$style.root"> <div :class="$style.root">
<img :class="$style.img" :src="serverErrorImageUrl" draggable="false"/> <img :class="$style.img" :src="serverErrorImageUrl" draggable="false"/>
@ -30,7 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkButton v-if="!list.isLiked" v-tooltip="i18n.ts.like" inline :class="$style.button" asLike @click="like()"><i class="ti ti-heart"></i><span v-if="1 > 0" class="count">{{ list.likedCount }}</span></MkButton> <MkButton v-if="!list.isLiked" v-tooltip="i18n.ts.like" inline :class="$style.button" asLike @click="like()"><i class="ti ti-heart"></i><span v-if="1 > 0" class="count">{{ list.likedCount }}</span></MkButton>
<MkButton inline @click="create()"><i class="ti ti-download" :class="$style.import"></i>{{ i18n.ts.import }}</MkButton> <MkButton inline @click="create()"><i class="ti ti-download" :class="$style.import"></i>{{ i18n.ts.import }}</MkButton>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="800"> <MkSpacer :contentMax="800">
<div v-if="state === 'done'" class="_buttonsCenter"> <div v-if="state === 'done'" class="_buttonsCenter">
<MkButton @click="close">{{ i18n.ts.close }}</MkButton> <MkButton @click="close">{{ i18n.ts.close }}</MkButton>
@ -15,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkLoading/> <MkLoading/>
</div> </div>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -31,7 +30,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(location.href).searchParams; const params = new URL(window.location.href).searchParams;
// acctdeprecated // acctdeprecated
let uri = params.get('uri') ?? params.get('acct'); let uri = params.get('uri') ?? params.get('acct');
@ -76,12 +75,12 @@ function close(): void {
// 100ms // 100ms
window.setTimeout(() => { window.setTimeout(() => {
location.href = '/'; window.location.href = '/';
}, 100); }, 100);
} }
function goToMisskey(): void { function goToMisskey(): void {
location.href = '/'; window.location.href = '/';
} }
fetch(); fetch();

View File

@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkPageWithAnimBg> <PageWithAnimBg>
<div :class="$style.formContainer"> <div :class="$style.formContainer">
<div :class="$style.form"> <div :class="$style.form">
<MkAuthConfirm <MkAuthConfirm
@ -24,13 +24,12 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkAuthConfirm> </MkAuthConfirm>
</div> </div>
</div> </div>
</MkPageWithAnimBg> </PageWithAnimBg>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, useTemplateRef } from 'vue'; import { computed, useTemplateRef } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import MkPageWithAnimBg from '@/components/MkPageWithAnimBg.vue';
import MkAuthConfirm from '@/components/MkAuthConfirm.vue'; import MkAuthConfirm from '@/components/MkAuthConfirm.vue';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { misskeyApi } from '@/utility/misskey-api.js'; import { misskeyApi } from '@/utility/misskey-api.js';
@ -61,7 +60,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);
location.href = cbUrl.toString(); window.location.href = cbUrl.toString();
} else { } else {
authRoot.value?.showUI('success'); authRoot.value?.showUI('success');
} }

View File

@ -4,11 +4,9 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkAntennaEditor @created="onAntennaCreated"/> <MkAntennaEditor @created="onAntennaCreated"/>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,11 +4,9 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkAntennaEditor v-if="antenna" :antenna="antenna" @updated="onAntennaUpdated"/> <MkAntennaEditor v-if="antenna" :antenna="antenna" @updated="onAntennaUpdated"/>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="700"> <MkSpacer :contentMax="700">
<div> <div>
<div v-if="antennas.length === 0" class="empty"> <div v-if="antennas.length === 0" class="empty">
@ -24,7 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</div> </div>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,23 +4,22 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="700"> <MkSpacer :contentMax="700">
<MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs"> <MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs">
<div v-if="tab === 'my'" key="my" class="_gaps"> <div v-if="tab === 'my'" class="_gaps">
<MkButton primary rounded class="add" @click="create"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton> <MkButton primary rounded class="add" @click="create"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton>
<MkPagination v-slot="{ items }" ref="pagingComponent" :pagination="pagination" class="_gaps"> <MkPagination v-slot="{ items }" ref="pagingComponent" :pagination="pagination" class="_gaps">
<MkClipPreview v-for="item in items" :key="item.id" :clip="item" :noUserInfo="true"/> <MkClipPreview v-for="item in items" :key="item.id" :clip="item" :noUserInfo="true"/>
</MkPagination> </MkPagination>
</div> </div>
<div v-else-if="tab === 'favorites'" key="favorites" class="_gaps"> <div v-else-if="tab === 'favorites'" class="_gaps">
<MkClipPreview v-for="item in favorites" :key="item.id" :clip="item"/> <MkClipPreview v-for="item in favorites" :key="item.id" :clip="item"/>
</div> </div>
</MkHorizontalSwipe> </MkHorizontalSwipe>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="700"> <MkSpacer :contentMax="700">
<div class="_gaps"> <div class="_gaps">
<div v-if="items.length === 0" class="empty"> <div v-if="items.length === 0" class="empty">
@ -25,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</div> </div>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="700" :class="$style.main"> <MkSpacer :contentMax="700" :class="$style.main">
<div v-if="list" class="_gaps"> <div v-if="list" class="_gaps">
<MkFolder> <MkFolder>
@ -49,7 +48,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkFolder> </MkFolder>
</div> </div>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<MkStickyContainer> <PageWithHeader :actions="headerActions" :tabs="headerTabs">
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="800"> <MkSpacer :contentMax="800">
<div> <div>
<Transition :name="prefer.s.animation ? 'fade' : ''" mode="out-in"> <Transition :name="prefer.s.animation ? 'fade' : ''" mode="out-in">
@ -44,7 +43,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</Transition> </Transition>
</div> </div>
</MkSpacer> </MkSpacer>
</MkStickyContainer> </PageWithHeader>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

Some files were not shown because too many files have changed in this diff Show More