This commit is contained in:
tamaina 2025-08-25 08:47:42 +09:00
parent 9c9e6c9ca9
commit 18bc7f6124
3 changed files with 24 additions and 17 deletions

View File

@ -2,19 +2,21 @@ import type { Directive } from 'vue';
let initialized = false; let initialized = false;
let styleEl: HTMLStyleElement | null = null; let styleEl: HTMLStyleElement | null = null;
const elements = new Set<HTMLElement>(); const canUseDeviceOrientation = !window.DeviceOrientationEvent;
const className = '_flipOnDeviceOrientation'; const className = '_flipOnDeviceOrientation';
const variableName = `--flip_on_device_orientation_transform`; const variableName = `--MI-flip_on_device_orientation_transform`;
function handleOrientationChange() { function handleOrientationChange(event: DeviceOrientationEvent) {
const isUpsideDown = window.screen.orientation.type === 'landscape-secondary'; const isUpsideDown = event.beta ? event.beta < -15 : false;
const transform = isUpsideDown ? 'scale(-1, -1)' : ''; const transform = isUpsideDown ? 'scale(-1, -1)' : '';
window.document.body.style.setProperty(variableName, transform); window.document.body.style.setProperty(variableName, transform);
} }
function registerListener() { function registerListener() {
if (!canUseDeviceOrientation) return;
if (!initialized) { if (!initialized) {
screen.orientation.addEventListener('change', handleOrientationChange); window.addEventListener('deviceorientation', handleOrientationChange);
if (!styleEl) { if (!styleEl) {
styleEl = window.document.createElement('style'); styleEl = window.document.createElement('style');
styleEl.textContent = `.${className} { transform: var(${variableName}); }`; styleEl.textContent = `.${className} { transform: var(${variableName}); }`;
@ -22,7 +24,7 @@ function registerListener() {
} }
initialized = true; initialized = true;
} else if (window.document.getElementsByClassName(className).length === 0) { } else if (window.document.getElementsByClassName(className).length === 0) {
screen.orientation.removeEventListener('change', handleOrientationChange); window.removeEventListener('deviceorientation', handleOrientationChange);
if (styleEl) { if (styleEl) {
window.document.head.removeChild(styleEl); window.document.head.removeChild(styleEl);
styleEl = null; styleEl = null;
@ -35,7 +37,6 @@ export default {
mounted(el) { mounted(el) {
registerListener(); registerListener();
el.classList.add(className); el.classList.add(className);
handleOrientationChange();
}, },
unmounted(el) { unmounted(el) {
el.classList.remove(className); el.classList.remove(className);

View File

@ -42,6 +42,8 @@ import { ensureSignin } from '@/i.js';
import { userPage, userName } from '@/filters/user.js'; import { userPage, userName } from '@/filters/user.js';
import misskeysvg from '/client-assets/misskey.svg'; import misskeysvg from '/client-assets/misskey.svg';
import MkAnimBg from '@/components/MkAnimBg.vue'; import MkAnimBg from '@/components/MkAnimBg.vue';
import { getStaticImageUrl } from '@/utility/media-proxy.js';
import { i18n } from '@/i18n.js';
const $i = ensureSignin(); const $i = ensureSignin();
@ -62,7 +64,8 @@ const avatarHsl = computed(() => avatarColor.value.toHsl());
const bgColor = tinycolor(`hsl(${avatarHsl.value.h}, 60, 46)`).toRgbString(); const bgColor = tinycolor(`hsl(${avatarHsl.value.h}, 60, 46)`).toRgbString();
function share() { function share() {
return navigator.share?.({ if (!canShare.value) return;
return navigator.share({
title: i18n.tsx._qr.shareTitle({ name: userName($i), acct: acct.value }), title: i18n.tsx._qr.shareTitle({ name: userName($i), acct: acct.value }),
text: i18n.tsx._qr.shareText({ name: userName($i), acct: acct.value }), text: i18n.tsx._qr.shareText({ name: userName($i), acct: acct.value }),
url: url.value, url: url.value,
@ -76,7 +79,7 @@ watch([qrCodeEl, avatarHsl, url], () => {
margin: 40, margin: 40,
type: 'canvas', type: 'canvas',
data: url.value, data: url.value,
image: instance.iconUrl ?? '/favicon.ico', image: instance.iconUrl ? getStaticImageUrl(instance.iconUrl) : '/favicon.ico',
qrOptions: { qrOptions: {
typeNumber: 0, typeNumber: 0,
mode: 'Byte', mode: 'Byte',
@ -142,7 +145,7 @@ watch([qrCodeEl, avatarHsl, url], () => {
.qrInner { .qrInner {
width: 100%; width: 100%;
max-height: 40dvh; max-height: 40dvh;
margin: 5dvh auto 2dvh; margin: 58px auto 32px;
> svg, > svg,
> canvas { > canvas {
@ -156,10 +159,10 @@ $avatarSize: 58px;
.user { .user {
display: flex; display: flex;
margin: 2dvh auto; margin: 32px auto;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
overflow: clip; overflow: visible;
width: fit-content; width: fit-content;
max-width: 100%; max-width: 100%;
} }
@ -178,7 +181,8 @@ $avatarSize: 58px;
align-items: start; align-items: start;
margin-top: -4px; margin-top: -4px;
max-width: 100%; max-width: 100%;
overflow: hidden; overflow-x: hidden;
overflow-y: visible;
} }
.name { .name {
@ -188,7 +192,8 @@ $avatarSize: 58px;
line-height: 24px; line-height: 24px;
width: fit-content; width: fit-content;
max-width: calc(100% - 16px); max-width: calc(100% - 16px);
overflow: hidden; overflow-x: hidden;
overflow-y: visible;
padding-right: 16px; padding-right: 16px;
mask-image: linear-gradient(90deg,#000,#000 calc(100% - 16px),#0000); mask-image: linear-gradient(90deg,#000,#000 calc(100% - 16px),#0000);
} }
@ -200,13 +205,14 @@ $avatarSize: 58px;
line-height: 16px; line-height: 16px;
width: fit-content; width: fit-content;
max-width: calc(100% - 16px); max-width: calc(100% - 16px);
overflow: hidden; overflow-x: hidden;
overflow-y: visible;
padding-right: 16px; padding-right: 16px;
mask-image: linear-gradient(90deg,#000,#000 calc(100% - 16px),#0000); mask-image: linear-gradient(90deg,#000,#000 calc(100% - 16px),#0000);
} }
.logo { .logo {
width: 30%; width: 30%;
margin: 2dvh auto 0; margin: 32px auto 0;
} }
</style> </style>

View File

@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<PageWithHeader v-model:tab="tab" :tabs="headerTabs" :swipable="true" :style="{ overflow: tab === 'show' ? 'clip' : undefined }"> <PageWithHeader v-model:tab="tab" :tabs="headerTabs" :swipable="true" :style="{ overflowY: tab === 'show' ? 'clip' : undefined }">
<MkQrShow v-if="tab === 'show'"/> <MkQrShow v-if="tab === 'show'"/>
<MkQrRead v-else-if="tab === 'read'"/> <MkQrRead v-else-if="tab === 'read'"/>
<MkError v-else-if="error" :error="error"/> <MkError v-else-if="error" :error="error"/>