This commit is contained in:
parent
79abac6f64
commit
268b303e0c
|
@ -4,14 +4,18 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
-->
|
||||
|
||||
<template>
|
||||
<div :class="[$style.root, accented ? $style.accented : null]"></div>
|
||||
<div :class="[$style.root, accented ? $style.accented : null, revered ? $style.revered : null]"/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const props = withDefaults(defineProps<{
|
||||
accented?: boolean;
|
||||
revered?: boolean;
|
||||
height?: number;
|
||||
}>(), {
|
||||
accented: false,
|
||||
revered: false,
|
||||
height: 200,
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -27,14 +31,17 @@ const props = withDefaults(defineProps<{
|
|||
--dot-size: 2px;
|
||||
--gap-size: 40px;
|
||||
--offset: calc(var(--gap-size) / 2);
|
||||
--height: v-bind('props.height + "px"');
|
||||
|
||||
height: 200px;
|
||||
margin-bottom: -200px;
|
||||
|
||||
height: var(--height);
|
||||
background-image: linear-gradient(transparent 60%, transparent 100%), radial-gradient(var(--c) var(--dot-size), transparent var(--dot-size)), radial-gradient(var(--c) var(--dot-size), transparent var(--dot-size));
|
||||
background-position: 0 0, 0 0, var(--offset) var(--offset);
|
||||
background-size: 100% 100%, var(--gap-size) var(--gap-size), var(--gap-size) var(--gap-size);
|
||||
mask-image: linear-gradient(to bottom, black 0%, transparent 100%);
|
||||
pointer-events: none;
|
||||
|
||||
&.revered {
|
||||
mask-image: linear-gradient(to top, black 0%, transparent 100%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<template>
|
||||
<PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs" :swipable="true">
|
||||
<MkPolkadots v-if="tab === 'home'" accented/>
|
||||
<MkPolkadots v-if="tab === 'home'" accented :height="200" style="margin-bottom: -200px;"/>
|
||||
<div class="_spacer" style="--MI_SPACER-w: 700px;">
|
||||
<XHome v-if="tab === 'home'"/>
|
||||
<XInvitations v-else-if="tab === 'invitations'"/>
|
||||
|
|
|
@ -4,39 +4,23 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
-->
|
||||
|
||||
<template>
|
||||
<div
|
||||
ref="rootEl" :class="$style.root" :style="{
|
||||
backgroundColor: bgColor,
|
||||
}"
|
||||
>
|
||||
<MkAnimBg style="position: absolute; top: 0;" :scale="1.5"/>
|
||||
<div :class="$style.fg">
|
||||
<div ref="rootEl" :class="$style.root">
|
||||
<div :class="[$style.content]">
|
||||
<div
|
||||
:class="[$style.content, '_spacer']"
|
||||
:style="{
|
||||
'--MI_SPACER-w': '512px',
|
||||
'--MI_SPACER-max': '14px',
|
||||
ref="qrCodeEl" v-flip :style="{
|
||||
'cursor': canShare ? 'pointer' : 'default',
|
||||
}"
|
||||
>
|
||||
<div
|
||||
:class="$style.qrOuter"
|
||||
:style="{
|
||||
'cursor': canShare ? 'pointer' : 'default',
|
||||
}"
|
||||
@click="share"
|
||||
>
|
||||
<div ref="qrCodeEl" v-flip :class="$style.qrInner"></div>
|
||||
:class="$style.qr" @click="share"
|
||||
></div>
|
||||
<div v-flip :class="$style.user">
|
||||
<MkAvatar :class="$style.avatar" :user="$i" :indicator="false"/>
|
||||
<div :class="$style.names">
|
||||
<div :class="$style.name"><MkCondensedLine :minScale="2 / 3"><MkUserName :user="$i" :nowrap="true"/></MkCondensedLine></div>
|
||||
<div :class="$style.username"><MkCondensedLine :minScale="2 / 3">{{ acct }}</MkCondensedLine></div>
|
||||
</div>
|
||||
<div v-flip :class="$style.user">
|
||||
<MkAvatar :class="$style.avatar" :user="$i" :indicator="false"/>
|
||||
<div :class="$style.names">
|
||||
<div :class="$style.name"><MkCondensedLine :minScale="2 / 3"><MkUserName :user="$i" :nowrap="true"/></MkCondensedLine></div>
|
||||
<div :class="$style.username"><MkCondensedLine :minScale="2 / 3">{{ acct }}</MkCondensedLine></div>
|
||||
</div>
|
||||
</div>
|
||||
<img v-if="deviceMotionPermissionNeeded" v-flip :class="$style.logo" :src="misskeysvg" alt="Misskey Logo" @click="requestDeviceMotion"/>
|
||||
<img v-else v-flip :class="$style.logo" :src="misskeysvg" alt="Misskey Logo"/>
|
||||
</div>
|
||||
<img v-if="deviceMotionPermissionNeeded" v-flip :class="$style.logo" :src="misskeysvg" alt="Misskey Logo" @click="requestDeviceMotion"/>
|
||||
<img v-else v-flip :class="$style.logo" :src="misskeysvg" alt="Misskey Logo"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -73,12 +57,7 @@ const canShare = computed(() => navigator.canShare && navigator.canShare(shareDa
|
|||
|
||||
const qrCodeEl = ref<HTMLDivElement | null>(null);
|
||||
|
||||
const avatarColor = computed(() => tinycolor(
|
||||
$i.avatarBlurhash ?
|
||||
extractAvgColorFromBlurhash($i.avatarBlurhash)
|
||||
: instance.themeColor
|
||||
?? '#86b300',
|
||||
));
|
||||
const avatarColor = computed(() => tinycolor(instance.themeColor ?? '#86b300'));
|
||||
const avatarHsl = computed(() => avatarColor.value.toHsl());
|
||||
const bgColor = tinycolor(`hsl(${avatarHsl.value.h}, 60, 46)`).toRgbString();
|
||||
|
||||
|
@ -90,7 +69,7 @@ function share() {
|
|||
const qrCodeInstance = new QRCodeStyling({
|
||||
width: 600,
|
||||
height: 600,
|
||||
margin: 36,
|
||||
margin: 42,
|
||||
type: 'canvas',
|
||||
data: `${url}/users/${$i.id}`,
|
||||
image: instance.iconUrl ? getStaticImageUrl(instance.iconUrl) : '/favicon.ico',
|
||||
|
@ -107,16 +86,6 @@ const qrCodeInstance = new QRCodeStyling({
|
|||
},
|
||||
dotsOptions: {
|
||||
color: tinycolor(`hsl(${avatarHsl.value.h}, 100, 18)`).toRgbString(),
|
||||
gradient: {
|
||||
type: 'linear',
|
||||
rotation: 1, // radian
|
||||
colorStops: [
|
||||
{ offset: 0, color: tinycolor(`hsl(${avatarHsl.value.h}, 100, 25)`).toRgbString() },
|
||||
{ offset: 0.5, color: tinycolor(`hsl(${avatarHsl.value.h}, 100, 20)`).toRgbString() },
|
||||
{ offset: 1, color: tinycolor(`hsl(${avatarHsl.value.h}, 100, 6)`).toRgbString() },
|
||||
],
|
||||
},
|
||||
type: 'classy-rounded',
|
||||
},
|
||||
backgroundOptions: {
|
||||
color: tinycolor(`hsl(${avatarHsl.value.h}, 100, 97)`).toRgbString(),
|
||||
|
@ -188,19 +157,7 @@ $avatarSize: 58px;
|
|||
|
||||
.root {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
margin-top: calc( -1 * var(--MI-stickyTop) );
|
||||
margin-bottom: calc( -1 * var(--MI-stickyBottom) );
|
||||
height: fit-content;
|
||||
min-height: 100cqh;
|
||||
}
|
||||
|
||||
.fg {
|
||||
position: sticky;
|
||||
padding-top: var(--MI-stickyTop);
|
||||
padding-bottom: var(--MI-stickyBottom);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
.content {
|
||||
|
@ -208,32 +165,34 @@ $avatarSize: 58px;
|
|||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 0 auto;
|
||||
padding-top: $s1;
|
||||
}
|
||||
|
||||
.qrOuter {
|
||||
display: flex;
|
||||
.qr {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
padding: 0 0 $s3;
|
||||
max-height: max(256px, calc((100cqh - var(--MI-stickyTop, 0px) - var(--MI-stickyBottom, 0px)) * 0.55));
|
||||
}
|
||||
|
||||
.qrInner {
|
||||
margin: 0;
|
||||
max-width: 250px;
|
||||
border-radius: 8px;
|
||||
overflow: clip;
|
||||
aspect-ratio: 1;
|
||||
|
||||
> svg,
|
||||
> canvas {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
.user {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: $s3 auto;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
overflow: visible;
|
||||
width: fit-content;
|
||||
max-width: 100%;
|
||||
|
@ -242,44 +201,23 @@ $avatarSize: 58px;
|
|||
.avatar {
|
||||
width: $avatarSize;
|
||||
height: $avatarSize;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.names {
|
||||
display: flex;
|
||||
font-weight: bold;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: start;
|
||||
margin: -2px -2px 0 ($avatarSize * 0.25);
|
||||
padding-right: 16px;
|
||||
max-width: 100%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: visible;
|
||||
mask-image: linear-gradient(90deg,#000,#000 calc(100% - 16px),#0000);
|
||||
|
||||
}
|
||||
|
||||
.name {
|
||||
display: inline-block;
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
line-height: 21px;
|
||||
width: fit-content;
|
||||
max-width: 100%;
|
||||
overflow: visible;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.username {
|
||||
display: inline-block;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
font-size: 13px;
|
||||
line-height: 15px;
|
||||
width: fit-content;
|
||||
max-width: 100%;
|
||||
overflow: visible;
|
||||
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 25%;
|
||||
width: 100px;
|
||||
margin: $s3 auto 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -4,39 +4,34 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
-->
|
||||
|
||||
<template>
|
||||
<PageWithHeader v-model:tab="tab" :class="$style.root" :tabs="headerTabs" :swipable="true">
|
||||
<MkQrShow v-if="tab === 'show'"/>
|
||||
<MkQrRead v-else-if="tab === 'read'"/>
|
||||
<MkError v-else-if="error" :error="error"/>
|
||||
<MkLoading v-else/>
|
||||
</PageWithHeader>
|
||||
<div :class="$style.root" class="_pageScrollable">
|
||||
<div class="_spacer" style="min-height: 100%;">
|
||||
<MkButton v-if="read" :class="$style.button" rounded @click="read = false"><i class="ti ti-qrcode"></i> {{ i18n.ts._qr.showTabTitle }}</MkButton>
|
||||
<MkButton v-else :class="$style.button" rounded @click="read = true"><i class="ti ti-scan"></i> {{ i18n.ts._qr.readTabTitle }}</MkButton>
|
||||
|
||||
<MkQrRead v-if="read"/>
|
||||
<MkQrShow v-else/>
|
||||
</div>
|
||||
<MkPolkadots v-if="!read" accented revered :height="200" style="position: sticky; bottom: 0; margin-top: -200px;"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, ref, shallowRef } from 'vue';
|
||||
import MkQrShow from './qr.show.vue';
|
||||
import { definePage } from '@/page.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { ensureSignin } from '@/i';
|
||||
import MkQrShow from './qr.show.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkPolkadots from '@/components/MkPolkadots.vue';
|
||||
|
||||
// router definitionでloginRequiredが設定されているためエラーハンドリングしない
|
||||
const $i = ensureSignin();
|
||||
|
||||
const tab = ref<'read' | 'show'>('show');
|
||||
const error = ref<any>(null);
|
||||
const read = ref(false);
|
||||
|
||||
const MkQrRead = defineAsyncComponent(() => import('./qr.read.vue'));
|
||||
|
||||
const headerTabs = [{
|
||||
key: 'show',
|
||||
title: i18n.ts._qr.showTabTitle,
|
||||
icon: 'ti ti-qrcode',
|
||||
}, {
|
||||
key: 'read',
|
||||
title: i18n.ts._qr.readTabTitle,
|
||||
icon: 'ti ti-scan',
|
||||
}];
|
||||
|
||||
definePage(() => ({
|
||||
title: i18n.ts.qr,
|
||||
icon: 'ti ti-qrcode',
|
||||
|
@ -47,4 +42,8 @@ definePage(() => ({
|
|||
.root {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.button {
|
||||
margin: 0 auto 16px auto;
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue