1
0
mirror of https://git.boykissers.com/pawkey/pawkey-sk.git synced 2025-12-20 12:14:18 +00:00

feat!: extensive theme overhaul (#9)

This commit is contained in:
Leafus
2025-05-19 16:36:37 +00:00
committed by Bluey Heeler
parent fe54ebf2af
commit e42e7e1e94
24 changed files with 577 additions and 180 deletions

View File

@@ -24,7 +24,7 @@
panelHighlight: ':lighten<3<@panel', panelHighlight: ':lighten<3<@panel',
panelHeaderBg: ':lighten<3<@panel', panelHeaderBg: ':lighten<3<@panel',
panelHeaderFg: '@fg', panelHeaderFg: '@fg',
panelBorder: '" solid 1px var(--MI_THEME-divider)', panelBorder: 'solid 1px var(--MI_THEME-divider)',
thread: ':lighten<12<@panel', thread: ':lighten<12<@panel',
windowHeader: ':alpha<0.85<@panel', windowHeader: ':alpha<0.85<@panel',
popup: ':lighten<3<@panel', popup: ':lighten<3<@panel',

View File

@@ -0,0 +1,88 @@
{
"base": "dark",
"props": {
"accent": "#cba6f7",
"accentDarken": ":darken<10<@accent",
"accentLighten": ":lighten<10<@accent",
"accentedBg": ":alpha<0.15<@accent",
"focus": ":alpha<0.3<@accent",
"bg": "#11111b",
"acrylicBg": ":alpha<0.5<@bg",
"fg": "#cdd6f4",
"fgTransparentWeak": ":alpha<0.75<@fg",
"fgTransparent": ":alpha<0.5<@fg",
"fgHighlighted": ":lighten<3<@fg",
"fgOnAccent": "#000000",
"divider": "rgba(255, 255, 255, 0.1)",
"indicator": "@accent",
"panel": ":lighten<3<@bg",
"panelHighlight": ":lighten<3<@panel",
"panelHeaderBg": ":lighten<3<@panel",
"panelHeaderFg": "@fg",
"panelHeaderDivider": "rgba(0, 0, 0, 0)",
"panelBorder": "\" solid 1px var(--divider)",
"acrylicPanel": ":alpha<0.5<@panel",
"popup": ":lighten<3<@panel",
"shadow": "rgba(0, 0, 0, 0.3)",
"header": ":alpha<0.7<@panel",
"navBg": "@panel",
"navFg": "@fg",
"navHoverFg": ":lighten<17<@fg",
"navActive": "@accent",
"navIndicator": "@indicator",
"link": "#cba6f7",
"hashtag": "#cba6f7",
"mention": "@accent",
"mentionMe": "@mention",
"renote": "#eba0ac",
"modalBg": "rgba(0, 0, 0, 0.5)",
"scrollbarHandle": "rgba(255, 255, 255, 0.2)",
"scrollbarHandleHover": "rgba(255, 255, 255, 0.4)",
"dateLabelFg": "@fg",
"infoBg": "#cdd6f4",
"infoFg": "#fff",
"infoWarnBg": "#42321c",
"infoWarnFg": "#ffbd3e",
"switchBg": "rgba(255, 255, 255, 0.15)",
"cwBg": "#687390",
"cwFg": "#393f4f",
"cwHoverBg": "#707b97",
"buttonBg": "rgba(255, 255, 255, 0.05)",
"buttonHoverBg": "rgba(255, 255, 255, 0.1)",
"buttonGradateA": "@accent",
"buttonGradateB": ":hue<20<@accent",
"inputBorder": "rgba(255, 255, 255, 0.1)",
"inputBorderHover": "rgba(255, 255, 255, 0.2)",
"listItemHoverBg": "rgba(255, 255, 255, 0.03)",
"driveFolderBg": ":alpha<0.3<@accent",
"wallpaperOverlay": "rgba(0, 0, 0, 0.5)",
"badge": "#31b1ce",
"messageBg": "@bg",
"success": "#86b300",
"error": "#ec4137",
"warn": "#ecb637",
"codeString": "#ffb675",
"codeNumber": "#cfff9e",
"codeBoolean": "#c59eff",
"htmlThemeColor": "@bg",
"X2": ":darken<2<@panel",
"X3": "rgba(255, 255, 255, 0.05)",
"X4": "rgba(255, 255, 255, 0.1)",
"X5": "rgba(255, 255, 255, 0.05)",
"X6": "rgba(255, 255, 255, 0.15)",
"X7": "rgba(255, 255, 255, 0.05)",
"X8": ":lighten<5<@accent",
"X9": ":darken<5<@accent",
"X10": ":alpha<0.4<@accent",
"X11": "rgba(0, 0, 0, 0.3)",
"X12": "rgba(255, 255, 255, 0.1)",
"X13": "rgba(255, 255, 255, 0.15)",
"X14": ":alpha<0.5<@navBg",
"X15": ":alpha<0<@panel",
"X16": ":alpha<0.7<@panel",
"X17": ":alpha<0.8<@bg"
},
"author": "Leafus",
"id": "ec668ba7-7682-486a-a10f-b4a5b2717d92",
"name": "Puppy Space Theme"
}

View File

@@ -0,0 +1,94 @@
{
id: 'dark',
name: 'Pawkey Dark',
author: 'Leafus',
desc: 'Pawkey Dark theme from our own Colorscheme',
kind: 'dark',
props: {
accent: '#b89bea',
accentDarken: ':darken<10<@accent',
accentLighten: ':lighten<10<@accent',
accentedBg: ':alpha<0.15<@accent',
love: '#dd2e44',
focus: ':alpha<0.3<@accent',
bg: '#09090a',
acrylicBg: ':alpha<0.5<@bg',
fg: '#f7efff',
fgTransparentWeak: ':alpha<0.75<@fg',
fgTransparent: ':alpha<0.5<@fg',
fgHighlighted: ':lighten<3<@fg',
fgOnAccent: '#000000',
fgOnWhite: '#333',
divider: 'rgba(255, 255, 255, 0.1)',
indicator: '@accent',
panel: ':lighten<3<@bg',
panelHighlight: ':lighten<3<@panel',
panelHeaderBg: ':lighten<3<@panel',
panelHeaderFg: '@fg',
panelHeaderDivider: 'rgba(0, 0, 0, 0)',
panelBorder: 'solid 1px var(--MI_THEME-divider)',
thread: ':lighten<12<@panel',
acrylicPanel: ':alpha<0.5<@panel',
windowHeader: ':alpha<0.85<@panel',
popup: ':lighten<3<@panel',
shadow: 'rgba(0, 0, 0, 0.3)',
header: ':alpha<0.7<@panel',
navBg: '@panel',
navFg: '@fg',
navHoverFg: ':lighten<17<@fg',
navActive: '@accent',
navIndicator: '@indicator',
link: '#b89bea',
hashtag: '#b89bea',
mention: '@accent',
mentionMe: '@mention',
renote: '#fb96f9',
modalBg: 'rgba(0, 0, 0, 0.5)',
scrollbarHandle: 'rgba(255, 255, 255, 0.2)',
scrollbarHandleHover: 'rgba(255, 255, 255, 0.4)',
dateLabelFg: '@fg',
infoBg: '#adedff',
infoFg: '#fff',
infoWarnBg: '#704830',
infoWarnFg: '#fab387',
folderHeaderBg: 'rgba(255, 255, 255, 0.05)',
folderHeaderHoverBg: 'rgba(255, 255, 255, 0.1)',
buttonBg: ':lighten<5<@panel',
buttonHoverBg: ':lighten<10<@panel',
buttonGradateA: '@accent',
buttonGradateB: ':hue<20<@accent',
switchBg: 'rgba(255, 255, 255, 0.15)',
switchOffBg: 'rgba(255, 255, 255, 0.1)',
switchOffFg: ':alpha<0.8<@fg',
switchOnBg: '@accentedBg',
switchOnFg: '@accent',
inputBorder: 'rgba(255, 255, 255, 0.1)',
inputBorderHover: 'rgba(255, 255, 255, 0.2)',
driveFolderBg: ':alpha<0.3<@accent',
wallpaperOverlay: 'rgba(0, 0, 0, 0.5)',
badge: '#89dceb',
messageBg: '@bg',
success: '#c3ffad',
error: '#ff5557',
warn: '#f9e2af',
codeString: '#ffb675',
codeNumber: '#cfff9e',
codeBoolean: '#c59eff',
deckBg: '#000',
htmlThemeColor: '@bg',
X3: 'rgba(255, 255, 255, 0.05)',
X4: 'rgba(255, 255, 255, 0.1)',
X5: 'rgba(255, 255, 255, 0.05)',
X6: 'rgba(255, 255, 255, 0.15)',
X7: 'rgba(255, 255, 255, 0.05)',
X11: 'rgba(0, 0, 0, 0.3)',
X12: 'rgba(255, 255, 255, 0.1)',
X13: 'rgba(255, 255, 255, 0.15)',
},
codeHighlighter: {
base: 'one-dark-pro',
},
}

View File

@@ -4,16 +4,42 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<div v-if="instance" :class="$style.root" :style="{ backgroundImage: `url(${ instance.backgroundImageUrl })` }"></div> <template v-if="instance">
<video v-if="isVideo" :class="$style.root" :src="instance.backgroundImageUrl" autoplay loop muted
playsinline></video>
<div v-else :class="$style.root" :style="{ backgroundImage: `url(${instance.backgroundImageUrl})` }"></div>
</template>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { instance } from '@/instance.js'; import { instance } from '@/instance.js';
import { computed } from 'vue';
const isVideo = computed(() => {
if (!instance?.backgroundImageUrl) return false;
const url = instance.backgroundImageUrl.toLowerCase();
return url.endsWith('.mp4') || url.endsWith('.webm') || url.endsWith('.ogg');
});
</script> </script>
<style lang="scss" module> <style lang="scss" module>
.root { .root {
background-position: center; background-position: center;
background-size: cover; background-size: cover;
position: fixed;
width: 100%;
height: 100%;
object-fit: cover;
top: 0px;
left: 0px;
}
video {
position: fixed;
width: 100%;
height: 100%;
object-fit: cover;
top: 0px;
left: 0px;
} }
</style> </style>

View File

@@ -27,6 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #user> <template #user>
<MkA v-user-preview="note.userId" :class="$style.renoteUserName" :to="userPage(note.user)"> <MkA v-user-preview="note.userId" :class="$style.renoteUserName" :to="userPage(note.user)">
<MkUserName :user="note.user"/> <MkUserName :user="note.user"/>
<MkAvatar :user="note.user"/>
</MkA> </MkA>
</template> </template>
</I18n> </I18n>
@@ -495,7 +496,7 @@ if (!props.mock) {
} }
} }
function boostVisibility(forceMenu: boolean = false) { function boostVisibility(forceMenu = false) {
if (renoting) return; if (renoting) return;
if (!prefer.s.showVisibilitySelectorOnBoost && !forceMenu) { if (!prefer.s.showVisibilitySelectorOnBoost && !forceMenu) {
@@ -505,7 +506,7 @@ function boostVisibility(forceMenu: boolean = false) {
} }
} }
function renote(visibility: Visibility, localOnly: boolean = false) { function renote(visibility: Visibility, localOnly = false) {
pleaseLogin({ openOnRemote: pleaseLoginContext.value }); pleaseLogin({ openOnRemote: pleaseLoginContext.value });
showMovedDialog(); showMovedDialog();
@@ -1204,9 +1205,12 @@ function emitUpdReaction(emoji: string, delta: number) {
margin: 0; margin: 0;
padding: 8px; padding: 8px;
opacity: 0.7; opacity: 0.7;
border-radius: var(--MI-radius-sm);
transition: all 300ms;
&:hover { &:hover {
color: var(--MI_THEME-fgHighlighted); background: color-mix(in srgb, var(--MI_THEME-renote) 10%, transparent) !important;
color: var(--MI_THEME-renote);
} }
} }

View File

@@ -498,7 +498,7 @@ useTooltip(quoteButton, async (showing) => {
}); });
}); });
function boostVisibility(forceMenu: boolean = false) { function boostVisibility(forceMenu = false) {
if (renoting) return; if (renoting) return;
if (!prefer.s.showVisibilitySelectorOnBoost && !forceMenu) { if (!prefer.s.showVisibilitySelectorOnBoost && !forceMenu) {
@@ -532,7 +532,7 @@ if (appearNote.value.reactionAcceptance === 'likeOnly') {
}); });
} }
function renote(visibility: Visibility, localOnly: boolean = false) { function renote(visibility: Visibility, localOnly = false) {
pleaseLogin({ openOnRemote: pleaseLoginContext.value }); pleaseLogin({ openOnRemote: pleaseLoginContext.value });
showMovedDialog(); showMovedDialog();
@@ -1084,9 +1084,12 @@ function animatedMFM() {
margin: 0; margin: 0;
padding: 8px; padding: 8px;
opacity: 0.7; opacity: 0.7;
border-radius: var(--MI-radius-sm);
transition: all 300ms;
&:hover { &:hover {
color: var(--MI_THEME-fgHighlighted); background: color-mix(in srgb, var(--MI_THEME-renote) 10%, transparent) !important;
color: var(--MI_THEME-renote);
} }
} }

View File

@@ -302,7 +302,7 @@ function boostVisibility(forceMenu: boolean = false) {
} }
} }
function renote(visibility: Visibility, localOnly: boolean = false) { function renote(visibility: Visibility, localOnly = false) {
pleaseLogin({ openOnRemote: pleaseLoginContext.value }); pleaseLogin({ openOnRemote: pleaseLoginContext.value });
showMovedDialog(); showMovedDialog();
@@ -459,11 +459,14 @@ if (props.detail) {
.noteFooterButton { .noteFooterButton {
margin: 0; margin: 0;
padding: 8px; padding: 8px;
padding-top: 10px;
opacity: 0.7; opacity: 0.7;
margin-top: 10px;
border-radius: var(--MI-radius-sm);
transition: all 300ms;
&:hover { &:hover {
color: var(--MI_THEME-fgHighlighted); background: color-mix(in srgb, var(--MI_THEME-renote) 10%, transparent) !important;
color: var(--MI_THEME-renote);
} }
} }

View File

@@ -6,19 +6,21 @@ SPDX-License-Identifier: AGPL-3.0-only
<template> <template>
<div :class="$style.wrapper" data-cy-signin-page-password> <div :class="$style.wrapper" data-cy-signin-page-password>
<div class="_gaps" :class="$style.root"> <div class="_gaps" :class="$style.root">
<div :class="$style.avatar" :style="{ backgroundImage: user ? `url('${user.avatarUrl}')` : undefined }"></div> <div :class="$style.avatar">
<i class="ti ti-user"></i>
</div>
<div :class="$style.welcomeBackMessage"> <div :class="$style.welcomeBackMessage">
<I18n :src="i18n.ts.welcomeBackWithName" tag="span"> <I18n :src="i18n.ts.welcomeBackWithName" tag="span">
<template #name><Mfm :text="user.name ?? user.username" :plain="true"/></template> <template #name><Mfm :text="username || 'User'" :plain="true"/></template>
</I18n> </I18n>
</div> </div>
<!-- password入力 --> <!-- password入力 -->
<form class="_gaps_s" @submit.prevent="onSubmit"> <form class="_gaps_s" @submit.prevent="onSubmit">
<!-- ブラウザ オートコンプリート用 --> <!-- ブラウザ オートコンプリート用 -->
<input type="hidden" name="username" autocomplete="username" :value="user.username"> <input type="hidden" name="username" autocomplete="username" :value="username">
<MkInput v-model="password" :placeholder="i18n.ts.password" type="password" autocomplete="current-password webauthn" :withPasswordToggle="true" required autofocus data-cy-signin-password> <MkInput v-model="password" :placeholder="i18n.ts.password" type="password" autocomplete="current-password webauthn" :withPasswordToggle="true" required autofocus data-cy-signin-page-password>
<template #prefix><i class="ti ti-lock"></i></template> <template #prefix><i class="ti ti-lock"></i></template>
<template #caption><button class="_textButton" type="button" @click="resetPassword">{{ i18n.ts.forgotPassword }}</button></template> <template #caption><button class="_textButton" type="button" @click="resetPassword">{{ i18n.ts.forgotPassword }}</button></template>
</MkInput> </MkInput>
@@ -29,7 +31,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkCaptcha v-if="instance.enableRecaptcha" ref="recaptcha" v-model="reCaptchaResponse" provider="recaptcha" :sitekey="instance.recaptchaSiteKey"/> <MkCaptcha v-if="instance.enableRecaptcha" ref="recaptcha" v-model="reCaptchaResponse" provider="recaptcha" :sitekey="instance.recaptchaSiteKey"/>
<MkCaptcha v-if="instance.enableTurnstile" ref="turnstile" v-model="turnstileResponse" provider="turnstile" :sitekey="instance.turnstileSiteKey"/> <MkCaptcha v-if="instance.enableTurnstile" ref="turnstile" v-model="turnstileResponse" provider="turnstile" :sitekey="instance.turnstileSiteKey"/>
<MkCaptcha v-if="instance.enableFC" ref="fc" v-model="fcResponse" provider="fc" :sitekey="instance.fcSiteKey"/> <MkCaptcha v-if="instance.enableFC" ref="fc" v-model="fcResponse" provider="fc" :sitekey="instance.fcSiteKey"/>
<MkCaptcha v-if="instance.enableTestcaptcha" ref="testcaptcha" v-model="testcaptchaResponse" provider="testcaptcha"/> <MkCaptcha v-if="instance.enableTestcaptcha" ref="testcaptcha" v-model="testcaptchaResponse" provider="testcaptcha" :sitekey="null"/>
</div> </div>
<MkButton type="submit" :disabled="needCaptcha && captchaFailed" large primary rounded style="margin: 0 auto;" data-cy-signin-page-password-continue>{{ i18n.ts.continue }} <i class="ti ti-arrow-right"></i></MkButton> <MkButton type="submit" :disabled="needCaptcha && captchaFailed" large primary rounded style="margin: 0 auto;" data-cy-signin-page-password-continue>{{ i18n.ts.continue }} <i class="ti ti-arrow-right"></i></MkButton>
@@ -53,7 +55,7 @@ export type PwResponse = {
</script> </script>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, useTemplateRef, defineAsyncComponent } from 'vue'; import { ref, computed, useTemplateRef, defineAsyncComponent, onMounted, watch } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import { instance } from '@/instance.js'; import { instance } from '@/instance.js';
@@ -65,7 +67,8 @@ import MkInput from '@/components/MkInput.vue';
import MkCaptcha from '@/components/MkCaptcha.vue'; import MkCaptcha from '@/components/MkCaptcha.vue';
const props = defineProps<{ const props = defineProps<{
user: Misskey.entities.UserDetailed; user?: Misskey.entities.UserDetailed | null;
username: string;
needCaptcha: boolean; needCaptcha: boolean;
}>(); }>();
@@ -129,6 +132,14 @@ function resetCaptcha() {
testcaptcha.value?.reset(); testcaptcha.value?.reset();
} }
onMounted(() => {
console.log('XPassword mounted with username:', props.username);
});
watch(() => props.username, (newUsername) => {
console.log('Username changed in XPassword:', newUsername);
});
defineExpose({ defineExpose({
resetCaptcha, resetCaptcha,
}); });
@@ -147,13 +158,15 @@ defineExpose({
} }
.avatar { .avatar {
margin: 0 auto 0 auto; margin: 0 auto;
width: 64px; background-color: color-mix(in srgb, var(--MI_THEME-fg), transparent 85%);
color: color-mix(in srgb, var(--MI_THEME-fg), transparent 25%);
text-align: center;
height: 64px; height: 64px;
background: #ddd; width: 64px;
background-position: center; font-size: 24px;
background-size: cover; line-height: 64px;
border-radius: 100%; border-radius: 50%;
} }
.welcomeBackMessage { .welcomeBackMessage {

View File

@@ -31,7 +31,7 @@ SPDX-License-Identifier: AGPL-3.0-only
key="password" key="password"
ref="passwordPageEl" ref="passwordPageEl"
:user="userInfo!" :username="userInfo?.username ?? ''"
:needCaptcha="needCaptcha" :needCaptcha="needCaptcha"
@passwordSubmitted="onPasswordSubmitted" @passwordSubmitted="onPasswordSubmitted"
@@ -159,13 +159,23 @@ function onUseTotp(): void {
async function onUsernameSubmitted(username: string) { async function onUsernameSubmitted(username: string) {
waiting.value = true; waiting.value = true;
console.log('Username submitted:', username);
// Store the username even if the API call fails
const submittedUsername = username;
// Only fetch user info if we don't already have it
if (!userInfo.value || userInfo.value.username !== username) {
userInfo.value = await misskeyApi('users/show', { userInfo.value = await misskeyApi('users/show', {
username, username,
}).catch(() => null); }).catch(() => {
// If the API call fails, create a minimal user object with just the username
return { username } as Misskey.entities.UserDetailed;
});
}
await tryLogin({ await tryLogin({
username, username: submittedUsername,
}); });
} }
@@ -188,9 +198,7 @@ async function onPasswordSubmitted(pw: PwResponse) {
'hcaptcha-response': pw.captcha.hCaptchaResponse, 'hcaptcha-response': pw.captcha.hCaptchaResponse,
'm-captcha-response': pw.captcha.mCaptchaResponse, 'm-captcha-response': pw.captcha.mCaptchaResponse,
'g-recaptcha-response': pw.captcha.reCaptchaResponse, 'g-recaptcha-response': pw.captcha.reCaptchaResponse,
'frc-captcha-solution': pw.captcha.fcResponse,
'turnstile-response': pw.captcha.turnstileResponse, 'turnstile-response': pw.captcha.turnstileResponse,
'testcaptcha-response': pw.captcha.testcaptchaResponse,
}); });
} }
} }
@@ -238,11 +246,13 @@ async function tryLogin(req: Partial<Misskey.entities.SigninFlowRequest>): Promi
case 'captcha': { case 'captcha': {
needCaptcha.value = true; needCaptcha.value = true;
page.value = 'password'; page.value = 'password';
console.log('Page changed to password (captcha), userInfo:', userInfo.value);
break; break;
} }
case 'password': { case 'password': {
needCaptcha.value = false; needCaptcha.value = false;
page.value = 'password'; page.value = 'password';
console.log('Page changed to password, userInfo:', userInfo.value);
break; break;
} }
case 'totp': { case 'totp': {

View File

@@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
> >
<div v-if="showing" :class="$style.root" class="_popup _shadow" :style="{ zIndex, top: top + 'px', left: left + 'px' }" @mouseover="() => { emit('mouseover'); }" @mouseleave="() => { emit('mouseleave'); }"> <div v-if="showing" :class="$style.root" class="_popup _shadow" :style="{ zIndex, top: top + 'px', left: left + 'px' }" @mouseover="() => { emit('mouseover'); }" @mouseleave="() => { emit('mouseleave'); }">
<div v-if="user != null"> <div v-if="user != null">
<div :class="$style.banner" :style="user.bannerUrl ? { backgroundImage: `url(${prefer.s.disableShowingAnimatedImages ? getStaticImageUrl(user.bannerUrl) : user.bannerUrl})` } : ''"> <div :class="$style.banner" :style="user.bannerUrl ? `background-image: url(${prefer.s.disableShowingAnimatedImages ? getStaticImageUrl(user.bannerUrl) : user.bannerUrl})` : ''">
<span v-if="$i && $i.id != user.id && user.isFollowed && user.isFollowing" :class="$style.followed">{{ i18n.ts.mutuals }}</span> <span v-if="$i && $i.id != user.id && user.isFollowed && user.isFollowing" :class="$style.followed">{{ i18n.ts.mutuals }}</span>
<span v-else-if="$i && $i.id != user.id && user.isFollowed" :class="$style.followed">{{ i18n.ts.followsYou }}</span> <span v-else-if="$i && $i.id != user.id && user.isFollowed" :class="$style.followed">{{ i18n.ts.followsYou }}</span>
<span v-else-if="$i && $i.id != user.id && user.isFollowing" :class="$style.followed">{{ i18n.ts.following }}</span> <span v-else-if="$i && $i.id != user.id && user.isFollowing" :class="$style.followed">{{ i18n.ts.following }}</span>
@@ -21,7 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
<svg viewBox="0 0 128 128" :class="$style.avatarBack"> <svg viewBox="0 0 128 128" :class="$style.avatarBack">
<g transform="matrix(1.6,0,0,1.6,-38.4,-51.2)"> <g transform="matrix(1.6,0,0,1.6,-38.4,-51.2)">
<path d="M64,32C81.661,32 96,46.339 96,64C95.891,72.184 104,72 104,72C104,72 74.096,80 64,80C52.755,80 24,72 24,72C24,72 31.854,72.018 32,64C32,46.339 46.339,32 64,32Z" style="fill: var(--MI_THEME-popup);"/> <path d="M64,32C81.661,32 96,46.339 96,64C96,72 104,72 104,72C104,72 74.096,80 64,80C52.755,80 24,72 24,72C24,72 32,72 32,64C32,46.339 46.339,32 64,32Z" style="fill: var(--MI_THEME-popup);"/>
</g> </g>
</svg> </svg>
<MkAvatar :class="$style.avatar" :user="user" indicator/> <MkAvatar :class="$style.avatar" :user="user" indicator/>

View File

@@ -4,11 +4,13 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<div v-if="instance" :class="$style.root">
<PwVisitorMusic/> <PwVisitorMusic/>
<div v-if="instance" :class="$style.root">
<div :class="[$style.main, $style.panel]"> <div :class="[$style.main, $style.panel]">
<img :src="instance.sidebarLogoUrl || instance.iconUrl || '/apple-touch-icon.png'" alt="" :class="instance.sidebarLogoUrl ? $style.wideIcon : $style.mainIcon"/> <img :src="instance.sidebarLogoUrl || instance.iconUrl || '/apple-touch-icon.png'" alt=""
<button class="_button _acrylic" :class="$style.mainMenu" @click="showMenu"><i class="ti ti-dots"></i></button> :class="instance.sidebarLogoUrl ? $style.wideIcon : $style.mainIcon" />
<button class="_button _acrylic" :class="$style.mainMenu" @click="showMenu"><i
class="ti ti-dots"></i></button>
<div :class="$style.mainFg"> <div :class="$style.mainFg">
<h1 :class="$style.mainTitle"> <h1 :class="$style.mainTitle">
<!-- 背景色によってはロゴが見えなくなるのでとりあえず無効に --> <!-- 背景色によってはロゴが見えなくなるのでとりあえず無効に -->
@@ -19,7 +21,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<!-- eslint-disable-next-line vue/no-v-html --> <!-- eslint-disable-next-line vue/no-v-html -->
<div v-html="sanitizeHtml(instance.description) || i18n.ts.headlineMisskey"></div> <div v-html="sanitizeHtml(instance.description) || i18n.ts.headlineMisskey"></div>
</div> </div>
<div v-if="instance.disableRegistration || instance.federation !== 'all'" :class="$style.mainWarn" class="_gaps_s"> <div v-if="instance.disableRegistration || instance.federation !== 'all'" :class="$style.mainWarn"
class="_gaps_s">
<MkInfo v-if="instance.disableRegistration" warn>{{ i18n.ts.invitationRequiredToRegister }}</MkInfo> <MkInfo v-if="instance.disableRegistration" warn>{{ i18n.ts.invitationRequiredToRegister }}</MkInfo>
<MkInfo v-if="instance.federation === 'specified'" warn>{{ i18n.ts.federationSpecified }}</MkInfo> <MkInfo v-if="instance.federation === 'specified'" warn>{{ i18n.ts.federationSpecified }}</MkInfo>
<MkInfo v-else-if="instance.federation === 'none'" warn>{{ i18n.ts.federationDisabled }}</MkInfo> <MkInfo v-else-if="instance.federation === 'none'" warn>{{ i18n.ts.federationDisabled }}</MkInfo>
@@ -28,28 +31,53 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkInfo warn>{{ i18n.ts.approvalRequiredToRegister }}</MkInfo> <MkInfo warn>{{ i18n.ts.approvalRequiredToRegister }}</MkInfo>
</div> </div>
<div class="_gaps_s" :class="$style.mainActions"> <div class="_gaps_s" :class="$style.mainActions">
<MkButton :class="$style.mainAction" full rounded gradate data-cy-signup style="margin-right: 12px;" @click="signup()">{{ i18n.ts.joinThisServer }}</MkButton> <MkButton :class="$style.mainAction" full rounded gradate data-cy-signup style="margin-right: 12px;"
<MkButton v-if="instance.policies.ltlAvailable" :class="$style.mainAction" full rounded link to="/explore">{{ i18n.ts.explore }}</MkButton> @click="signup()">{{ i18n.ts.joinThisServer }}</MkButton>
<MkButton :class="$style.mainAction" full rounded data-cy-signin @click="signin()">{{ i18n.ts.login }}</MkButton> <MkButton :class="$style.mainAction" full rounded data-cy-signin @click="signin()">{{ i18n.ts.login
}}</MkButton>
</div>
</div>
<div
v-if="instance.disableRegistration || instance.federation !== 'all'" :class="$style.mainWarn"
class="_gaps_s"
>
<MkInfo v-if="instance.disableRegistration" warn>{{ i18n.ts.invitationRequiredToRegister }}</MkInfo>
<MkInfo v-if="instance.federation === 'specified'" warn>{{ i18n.ts.federationSpecified }}</MkInfo>
<MkInfo v-else-if="instance.federation === 'none'" warn>{{ i18n.ts.federationDisabled }}</MkInfo>
</div>
<div v-if="instance.approvalRequiredForSignup" :class="$style.mainWarn">
<MkInfo warn>{{ i18n.ts.approvalRequiredToRegister }}</MkInfo>
</div>
<div :class="$style.mainActions">
<MkButton :class="$style.mainAction" full rounded gradate data-cy-signup @click="signup()">
{{ i18n.ts.joinThisServer }}
</MkButton>
<MkButton :class="$style.mainAction" full rounded data-cy-signin @click="signin()">
{{ i18n.ts.login }}
</MkButton>
</div> </div>
</div> </div>
</div> </div>
<div v-if="stats" :class="$style.stats"> <div v-if="stats" :class="$style.stats">
<div :class="[$style.statsItem, $style.panel]"> <div :class="[$style.statsItem, $style.panel]">
<div :class="$style.statsItemLabel">{{ i18n.ts.users }}</div> <div :class="$style.statsItemLabel">{{ i18n.ts.users }}</div>
<div :class="$style.statsItemCount"><MkNumber :value="stats.originalUsersCount"/></div> <div :class="$style.statsItemCount">
<MkNumber :value="stats.originalUsersCount"/>
</div>
</div> </div>
<div :class="[$style.statsItem, $style.panel]"> <div :class="[$style.statsItem, $style.panel]">
<div :class="$style.statsItemLabel">{{ i18n.ts.notes }}</div> <div :class="$style.statsItemLabel">{{ i18n.ts.notes }}</div>
<div :class="$style.statsItemCount"><MkNumber :value="stats.originalNotesCount"/></div> <div :class="$style.statsItemCount">
<MkNumber :value="stats.originalNotesCount"/>
</div> </div>
</div> </div>
<div v-if="instance.policies.ltlAvailable" :class="[$style.tl, $style.panel]"> </div>
<!-- <div v-if="instance.policies.ltlAvailable" :class="[$style.tl, $style.panel]">
<div :class="$style.tlHeader">{{ i18n.ts.letsLookAtTimeline }}</div> <div :class="$style.tlHeader">{{ i18n.ts.letsLookAtTimeline }}</div>
<div :class="$style.tlBody"> <div :class="$style.tlBody">
<MkTimeline src="local"/> <MkTimeline src="local"/>
</div> </div>
</div> </div> -->
<div :class="$style.panel"> <div :class="$style.panel">
<XActiveUsersChart/> <XActiveUsersChart/>
</div> </div>
@@ -59,14 +87,15 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { ref } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import sanitizeHtml from '@/utility/sanitize-html.js'; import { instanceName } from '@@/js/config.js';
import type { MenuItem } from '@/types/menu.js';
import sanitizeHtml from '@/scripts/sanitize-html.js';
import XSigninDialog from '@/components/MkSigninDialog.vue'; import XSigninDialog from '@/components/MkSigninDialog.vue';
import XSignupDialog from '@/components/MkSignupDialog.vue'; import XSignupDialog from '@/components/MkSignupDialog.vue';
import PwVisitorMusic from '@/components/PwVisitorMusic.vue'; import PwVisitorMusic from '@/components/PwVisitorMusic.vue';
import MkButton from '@/components/MkButton.vue'; import MkButton from '@/components/MkButton.vue';
import MkTimeline from '@/components/MkTimeline.vue'; import MkTimeline from '@/components/MkTimeline.vue';
import MkInfo from '@/components/MkInfo.vue'; import MkInfo from '@/components/MkInfo.vue';
import { instanceName } from '@@/js/config.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { misskeyApi } from '@/utility/misskey-api.js'; import { misskeyApi } from '@/utility/misskey-api.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
@@ -74,7 +103,6 @@ import { instance } from '@/instance.js';
import MkNumber from '@/components/MkNumber.vue'; import MkNumber from '@/components/MkNumber.vue';
import XActiveUsersChart from '@/components/MkVisitorDashboard.ActiveUsersChart.vue'; import XActiveUsersChart from '@/components/MkVisitorDashboard.ActiveUsersChart.vue';
import { openInstanceMenu } from '@/ui/_common_/common.js'; import { openInstanceMenu } from '@/ui/_common_/common.js';
import type { MenuItem } from '@/types/menu.js';
const stats = ref<Misskey.entities.StatsResponse | null>(null); const stats = ref<Misskey.entities.StatsResponse | null>(null);
@@ -114,8 +142,9 @@ function showMenu(ev: MouseEvent) {
.panel { .panel {
position: relative; position: relative;
background: var(--MI_THEME-panel);
border-radius: var(--MI-radius); border-radius: var(--MI-radius);
background: color-mix(in srgb, var(--MI_THEME-bg) 50%, transparent) !important;
backdrop-filter: blur(25px);
box-shadow: 0 12px 32px rgb(0 0 0 / 25%); box-shadow: 0 12px 32px rgb(0 0 0 / 25%);
} }
@@ -176,6 +205,9 @@ function showMenu(ev: MouseEvent) {
} }
.mainActions { .mainActions {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
padding: 32px; padding: 32px;
} }

View File

@@ -77,6 +77,7 @@ const themeColorStyle = computed<CSSProperties>(() => {
.icon { .icon {
height: 2ex; height: 2ex;
border-radius: 10px;
flex-shrink: 0; flex-shrink: 0;
} }

View File

@@ -28,6 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #user> <template #user>
<MkA v-user-preview="note.userId" :class="$style.renoteUserName" :to="userPage(note.user)"> <MkA v-user-preview="note.userId" :class="$style.renoteUserName" :to="userPage(note.user)">
<MkUserName :user="note.user"/> <MkUserName :user="note.user"/>
<MkAvatar :user="note.user"/>
</MkA> </MkA>
</template> </template>
</I18n> </I18n>
@@ -494,7 +495,7 @@ if (!props.mock) {
} }
} }
function boostVisibility(forceMenu: boolean = false) { function boostVisibility(forceMenu = false) {
if (renoting) return; if (renoting) return;
if (!prefer.s.showVisibilitySelectorOnBoost && !forceMenu) { if (!prefer.s.showVisibilitySelectorOnBoost && !forceMenu) {
@@ -504,7 +505,7 @@ function boostVisibility(forceMenu: boolean = false) {
} }
} }
function renote(visibility: Visibility, localOnly: boolean = false) { function renote(visibility: Visibility, localOnly = false) {
pleaseLogin({ openOnRemote: pleaseLoginContext.value }); pleaseLogin({ openOnRemote: pleaseLoginContext.value });
showMovedDialog(); showMovedDialog();
@@ -948,6 +949,12 @@ function emitUpdReaction(emoji: string, delta: number) {
.footerButton { .footerButton {
font-size: 90%; font-size: 90%;
color: var(--MI_THEME-renote);
background: color-mix(in srgb, var(--MI_THEME-renote) 10%, transparent) !important;
&:not(:last-child) {
margin-right: 0;
}
} }
} }
@@ -1020,7 +1027,6 @@ function emitUpdReaction(emoji: string, delta: number) {
.renoteAvatar { .renoteAvatar {
flex-shrink: 0; flex-shrink: 0;
display: none; /* same as Firefish, but keeping the element around in case someone wants to add it back via CSS override */
width: 28px; width: 28px;
height: 28px; height: 28px;
margin: 0 8px 0 0; margin: 0 8px 0 0;
@@ -1234,9 +1240,12 @@ function emitUpdReaction(emoji: string, delta: number) {
margin: 0; margin: 0;
padding: 8px; padding: 8px;
opacity: 0.7; opacity: 0.7;
border-radius: var(--MI-radius-sm);
transition: all 300ms;
&:hover { &:hover {
color: var(--MI_THEME-fgHighlighted); background: color-mix(in srgb, var(--MI_THEME-renote) 10%, transparent) !important;
color: var(--MI_THEME-renote);
} }
} }

View File

@@ -23,6 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #user> <template #user>
<MkA v-user-preview="note.userId" :class="$style.renoteName" :to="userPage(note.user)"> <MkA v-user-preview="note.userId" :class="$style.renoteName" :to="userPage(note.user)">
<MkUserName :user="note.user"/> <MkUserName :user="note.user"/>
<MkAvatar :user="note.user"/>
</MkA> </MkA>
</template> </template>
</I18n> </I18n>
@@ -503,7 +504,7 @@ useTooltip(quoteButton, async (showing) => {
}); });
}); });
function boostVisibility(forceMenu: boolean = false) { function boostVisibility(forceMenu = false) {
if (renoting) return; if (renoting) return;
if (!prefer.s.showVisibilitySelectorOnBoost && !forceMenu) { if (!prefer.s.showVisibilitySelectorOnBoost && !forceMenu) {
@@ -537,7 +538,7 @@ if (appearNote.value.reactionAcceptance === 'likeOnly') {
}); });
} }
function renote(visibility: Visibility, localOnly: boolean = false) { function renote(visibility: Visibility, localOnly = false) {
pleaseLogin({ openOnRemote: pleaseLoginContext.value }); pleaseLogin({ openOnRemote: pleaseLoginContext.value });
showMovedDialog(); showMovedDialog();
@@ -1143,9 +1144,12 @@ onUnmounted(() => {
margin: 0; margin: 0;
padding: 8px; padding: 8px;
opacity: 0.7; opacity: 0.7;
border-radius: var(--MI-radius-sm);
transition: all 300ms;
&:hover { &:hover {
color: var(--MI_THEME-fgHighlighted); background: color-mix(in srgb, var(--MI_THEME-renote) 10%, transparent) !important;
color: var(--MI_THEME-renote);
} }
} }
@@ -1167,6 +1171,7 @@ onUnmounted(() => {
border-top: solid 0.5px var(--MI_THEME-divider); border-top: solid 0.5px var(--MI_THEME-divider);
border-bottom: solid 0.5px var(--MI_THEME-divider); border-bottom: solid 0.5px var(--MI_THEME-divider);
display: flex; display: flex;
padding: 10px;
} }
.tab { .tab {
@@ -1177,6 +1182,7 @@ onUnmounted(() => {
padding: 12px 8px; padding: 12px 8px;
border-top: solid 2px transparent; border-top: solid 2px transparent;
border-bottom: solid 2px transparent; border-bottom: solid 2px transparent;
border-radius: var(--MI-radius-lg);
> i { > i {
margin-right: 8px; margin-right: 8px;
@@ -1184,7 +1190,8 @@ onUnmounted(() => {
} }
.tabActive { .tabActive {
border-bottom: solid 2px var(--MI_THEME-accent); background: color-mix(in srgb, var(--MI_THEME-accent) 10%, transparent) !important;
color: var(--MI_THEME-accent);
} }
.tab_renotes { .tab_renotes {

View File

@@ -316,7 +316,7 @@ function boostVisibility(forceMenu: boolean = false) {
} }
} }
function renote(visibility: Visibility, localOnly: boolean = false) { function renote(visibility: Visibility, localOnly = false) {
pleaseLogin({ openOnRemote: pleaseLoginContext.value }); pleaseLogin({ openOnRemote: pleaseLoginContext.value });
showMovedDialog(); showMovedDialog();
@@ -517,9 +517,12 @@ if (props.detail) {
padding: 8px; padding: 8px;
padding-top: 10px; padding-top: 10px;
opacity: 0.7; opacity: 0.7;
border-radius: var(--MI-radius-sm);
transition: all 300ms;
&:hover { &:hover {
color: var(--MI_THEME-fgHighlighted); background: color-mix(in srgb, var(--MI_THEME-renote) 10%, transparent) !important;
color: var(--MI_THEME-renote);
} }
} }
// Responsible for Reply borders 448 and 508 // Responsible for Reply borders 448 and 508

View File

@@ -28,10 +28,6 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</button> </button>
</div> </div>
<div
ref="tabHighlightEl"
:class="[$style.tabHighlight, { [$style.animate]: prefer.s.animation }]"
></div>
</div> </div>
</template> </template>
@@ -201,8 +197,10 @@ onUnmounted(() => {
} }
.tabsInner { .tabsInner {
display: inline-block; display: flex;
height: var(--height); align-items: center;
justify-content: center;
height: 100%;
white-space: nowrap; white-space: nowrap;
} }
@@ -210,9 +208,10 @@ onUnmounted(() => {
display: inline-block; display: inline-block;
position: relative; position: relative;
padding: 0 10px; padding: 0 10px;
height: 100%; color: var(--MI_THEME-accent);
height: 35px;
border-radius: var(--MI-radius-lg);
font-weight: normal; font-weight: normal;
opacity: 0.7;
&:hover { &:hover {
opacity: 1; opacity: 1;
@@ -220,7 +219,8 @@ onUnmounted(() => {
&.active { &.active {
opacity: 1; opacity: 1;
color: var(--MI_THEME-accent); background: color-mix(in srgb, var(--MI_THEME-accent) 10%, transparent) !important;
border-bottom: none !important;
} }
&.animate { &.animate {
@@ -243,19 +243,9 @@ onUnmounted(() => {
&.animate { &.animate {
transition: width .15s linear, padding-left .15s linear; transition: width .15s linear, padding-left .15s linear;
} }
}
.tabHighlight { @media (max-width: 500px) {
position: absolute; display: none;
bottom: 0;
height: 3px;
background: var(--MI_THEME-accent);
border-radius: var(--MI-radius-ellipse);
transition: none;
pointer-events: none;
&.animate {
transition: width 0.15s ease, left 0.15s ease;
} }
} }
</style> </style>

View File

@@ -150,13 +150,7 @@ onUnmounted(() => {
backdrop-filter: var(--MI-blur, blur(15px)); backdrop-filter: var(--MI-blur, blur(15px));
border-bottom: solid 0.5px transparent; border-bottom: solid 0.5px transparent;
width: 100%; width: 100%;
color: var(--MI_THEME-pageHeaderFg); overflow-y: scroll;
}
@container style(--MI_THEME-pageHeaderBg: var(--MI_THEME-bg)) {
.root {
border-bottom: solid 0.5px var(--MI_THEME-divider);
}
} }
.upper, .upper,
@@ -242,14 +236,16 @@ onUnmounted(() => {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
height: var(--height); width: 35px;
width: calc(var(--height) - (var(--margin))); margin-right: 10px;
height: 35px;
box-sizing: border-box; box-sizing: border-box;
position: relative; position: relative;
border-radius: var(--MI-radius-xs); border-radius: var(--MI-radius-lg);
color: var(--MI_THEME-accent);
&:hover { &:hover {
background: rgba(0, 0, 0, 0.05); background: color-mix(in srgb, var(--MI_THEME-accent) 10%, transparent) !important;
} }
&.highlighted { &.highlighted {

View File

@@ -862,8 +862,8 @@ onUnmounted(() => {
} }
.tab { .tab {
margin-bottom: calc(5px / 2); margin-bottom: calc(var(--MI-margin) / 2);
padding: calc(5px / 2) 0; padding: calc(var(--MI-margin) / 2) 0;
background: color-mix(in srgb, var(--MI_THEME-bg) 65%, transparent); background: color-mix(in srgb, var(--MI_THEME-bg) 65%, transparent);
backdrop-filter: var(--MI-blur, blur(15px)); backdrop-filter: var(--MI-blur, blur(15px));
border-radius: var(--MI-radius-sm); border-radius: var(--MI-radius-sm);

View File

@@ -7,11 +7,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="meta" :class="$style.root"> <div v-if="meta" :class="$style.root">
<MkFeaturedPhotos :class="$style.bg"/> <MkFeaturedPhotos :class="$style.bg"/>
<XTimeline v-if="meta.policies.ltlAvailable" :class="$style.tl"/> <XTimeline v-if="meta.policies.ltlAvailable" :class="$style.tl"/>
<div :class="$style.shape1"></div> <div class="logo-wrapper">
<div :class="$style.shape2"></div> <!-- <div class="powered-by">Powered by</div> -->
<div :class="$style.logoWrapper"> <img :src="misskeysvg" class="misskey"/>
<div :class="$style.poweredBy">Powered by</div>
<img :src="misskeysvg" :class="$style.misskey"/>
</div> </div>
<div class="emojis"> <div class="emojis">
<MkEmoji :normal="true" :noStyle="true" emoji="🐾"/> <MkEmoji :normal="true" :noStyle="true" emoji="🐾"/>
@@ -22,15 +20,15 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="contents"> <div class="contents">
<MkVisitorDashboard/> <MkVisitorDashboard/>
</div> </div>
<div v-if="instances && instances.length > 0" :class="$style.federation"> <!-- <div v-if="instances && instances.length > 0" class="federation">
<MarqueeText :duration="40"> <MarqueeText :duration="40">
<MkA v-for="instance in instances" :key="instance.id" :class="$style.federationInstance" :to="`/instance-info/${instance.host}`" behavior="window"> <MkA v-for="instance in instances" :key="instance.id" :class="$style.federationInstance" :to="`/instance-info/${instance.host}`" behavior="window">
<!--<MkInstanceCardMini :instance="instance"/>--> <MkInstanceCardMini :instance="instance"/>
<img v-if="instance.iconUrl" :class="$style.federationInstanceIcon" :src="getInstanceIcon(instance)" alt=""/> <img v-if="instance.iconUrl" class="icon" :src="getInstanceIcon(instance)" alt=""/>
<span class="_monospace">{{ instance.host }}</span> <span class="name _monospace">{{ instance.host }}</span>
</MkA> </MkA>
</MarqueeText> </MarqueeText>
</div> </div> -->
</div> </div>
</template> </template>
@@ -76,7 +74,7 @@ misskeyApiGet('federation/instances', {
position: fixed; position: fixed;
top: 0; top: 0;
right: 0; right: 0;
width: 80vw; // 100%からshapeの幅を引いている width: 100%;
height: 100vh; height: 100vh;
} }
@@ -98,26 +96,6 @@ misskeyApiGet('federation/instances', {
} }
} }
.shape1 {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: var(--MI_THEME-accent);
clip-path: polygon(0% 0%, 45% 0%, 20% 100%, 0% 100%);
}
.shape2 {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: var(--MI_THEME-accent);
clip-path: polygon(0% 0%, 25% 0%, 35% 100%, 0% 100%);
opacity: 0.5;
}
.logoWrapper { .logoWrapper {
position: fixed; position: fixed;
top: 36px; top: 36px;
@@ -141,10 +119,10 @@ misskeyApiGet('federation/instances', {
} }
} }
.contents { > .contents {
position: relative; position: relative;
width: min(430px, calc(100% - 32px)); width: min(500px, calc(100% - 32px));
margin-left: 128px; margin: auto;
padding: 100px 0 100px 0; padding: 100px 0 100px 0;
@media (max-width: 1200px) { @media (max-width: 1200px) {

View File

@@ -6,7 +6,7 @@
import { markRaw, ref } from 'vue'; import { markRaw, ref } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import lightTheme from '@@/themes/l-light.json5'; import lightTheme from '@@/themes/l-light.json5';
import darkTheme from '@@/themes/d-green-lime.json5'; import darkTheme from '@@/themes/pwDark.json5';
import { hemisphere } from '@@/js/intl-const.js'; import { hemisphere } from '@@/js/intl-const.js';
import type { DeviceKind } from '@/utility/device-kind.js'; import type { DeviceKind } from '@/utility/device-kind.js';
import type { Plugin } from '@/plugin.js'; import type { Plugin } from '@/plugin.js';

View File

@@ -15,14 +15,14 @@
*/ */
:root { :root {
--MI-radius-xs: 5px; --MI-radius-xs: 7px;
--MI-radius-sm: 5px; --MI-radius-sm: 9px;
--MI-radius: 5px; --MI-radius: 10px;
--MI-radius-md: 5px; --MI-radius-md: 12px;
--MI-radius-lg: 5px; --MI-radius-lg: 15px;
--MI-radius-xl: 5px; --MI-radius-xl: 18px;
--MI-radius-ellipse: 5px; --MI-radius-ellipse: 15px;
--MI-radius-full: 5px; --MI-radius-full: 25px;
--MI-marginFull: 16px; --MI-marginFull: 16px;
--MI-marginHalf: 10px; --MI-marginHalf: 10px;

View File

@@ -423,6 +423,9 @@ function getPointerEvents() {
bottom: 0; bottom: 0;
left: 0; left: 0;
z-index: 2147483647; z-index: 2147483647;
border-radius: 10px;
margin-top: 10px;
margin-left: 10px;
color: #ff0; color: #ff0;
background: rgba(0, 0, 0, 0.5); background: rgba(0, 0, 0, 0.5);
padding: 4px 5px; padding: 4px 5px;

View File

@@ -449,6 +449,7 @@ function menuEdit() {
position: relative; position: relative;
display: block; display: block;
padding-left: 30px; padding-left: 30px;
margin-bottom: 3px;
line-height: 2.85rem; line-height: 2.85rem;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;

View File

@@ -6,7 +6,13 @@ SPDX-License-Identifier: AGPL-3.0-only
<template> <template>
<div :class="$style.root"> <div :class="$style.root">
<div v-if="!narrow && !isRoot" :class="$style.side"> <div v-if="!narrow && !isRoot" :class="$style.side">
<div :class="$style.banner" :style="{ backgroundImage: instance.backgroundImageUrl ? `url(${ instance.backgroundImageUrl })` : 'none' }"></div> <div :class="$style.banner">
<video v-if="isVideo" :src="instance.backgroundImageUrl" autoplay loop muted playsinline></video>
<div v-else
class="image"
:style="{ backgroundImage: instance.backgroundImageUrl ? `url(${instance.backgroundImageUrl})` : 'none' }">
</div>
</div>
<div :class="$style.dashboard"> <div :class="$style.dashboard">
<MkVisitorDashboard /> <MkVisitorDashboard />
</div> </div>
@@ -71,10 +77,50 @@ onMounted(() => {
}, { passive: true }); }, { passive: true });
} }
}); });
const isVideo = computed(() => {
if (!instance?.backgroundImageUrl) return false;
const url = instance.backgroundImageUrl.toLowerCase();
return url.endsWith('.mp4') || url.endsWith('.webm') || url.endsWith('.ogg');
});
defineExpose({
showMenu: showMenu,
});
</script> </script>
<style> <style>
.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}} .github-corner:hover .octo-arm {
animation: octocat-wave 560ms ease-in-out
}
@keyframes octocat-wave {
0%,
100% {
transform: rotate(0)
}
20%,
60% {
transform: rotate(-25deg)
}
40%,
80% {
transform: rotate(10deg)
}
}
@media (max-width:500px) {
.github-corner:hover .octo-arm {
animation: none
}
.github-corner .octo-arm {
animation: octocat-wave 560ms ease-in-out
}
}
</style> </style>
<style lang="scss" module> <style lang="scss" module>
@@ -115,29 +161,119 @@ onMounted(() => {
background: var(--MI_THEME-accent); background: var(--MI_THEME-accent);
} }
.banner { >.banner {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
aspect-ratio: 1.5; height: 100%;
background-position: center; background-position: center;
background-size: cover; background-size: cover;
-webkit-mask-image: linear-gradient(rgba(0, 0, 0, 1.0), transparent); -webkit-mask-image: linear-gradient(rgba(0, 0, 0, 1.0), transparent);
mask-image: linear-gradient(rgba(0, 0, 0, 1.0), transparent); mask-image: linear-gradient(rgba(0, 0, 0, 1.0), transparent);
> video {
width: 500px;
height: 100%;
object-fit: cover;
} }
.dashboard { > .image {
width: 500px;
height: 100%;
background-size: cover;
background-position: center;
}
}
>.dashboard {
position: relative; position: relative;
padding: 32px; padding: 32px;
box-sizing: border-box; box-sizing: border-box;
max-height: 100%; max-height: 100%;
overflow: auto; overflow: auto;
} }
}
.content { >.main {
display: flex; flex: 1;
flex-direction: column; min-width: 0;
height: 100dvh;
>.header {
background: var(--MI_THEME-panel);
position: relative;
z-index: 1;
>.wide {
line-height: 50px;
padding: 0 16px;
>.link {
padding: 0 16px;
}
}
>.narrow {
>.menu {
padding: 16px;
}
}
}
}
>.menu-back {
position: fixed;
z-index: 1001;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
}
>.menu {
position: fixed;
z-index: 1001;
top: 0;
left: 0;
width: 240px;
height: 100vh;
background: var(--MI_THEME-panel);
>.link {
display: block;
padding: 16px;
>.icon {
margin-right: 1em;
}
}
>.divider {
margin: 8px auto;
width: calc(100% - 32px);
border-top: solid 0.5px var(--MI_THEME-divider);
}
>.action {
padding: 16px;
>button {
display: block;
width: 100%;
padding: 10px;
box-sizing: border-box;
text-align: center;
border-radius: var(--MI-radius-ellipse);
&._button {
background: var(--MI_THEME-panel);
}
&:first-child {
margin-bottom: 16px;
}
}
}
}
} }
</style> </style>