fix: modal positioning (#5796)

This commit is contained in:
Calum H.
2026-04-13 16:01:52 +02:00
committed by GitHub
parent 0713814d0c
commit c1b0e4a692
4 changed files with 39 additions and 28 deletions

View File

@@ -1,9 +1,6 @@
<template> <template>
<Teleport to="body"> <Teleport to="body">
<div <div v-if="open" class="modal-root">
v-if="open"
:style="`${mouseX !== -1 ? `--_mouse-x: ${mouseX};` : ''} ${mouseY !== -1 ? `--_mouse-y: ${mouseY};` : ''}`"
>
<div <div
:class="{ shown: visible }" :class="{ shown: visible }"
class="tauri-overlay" class="tauri-overlay"
@@ -21,14 +18,7 @@
]" ]"
@click="() => (closeOnClickOutside && closable ? hide() : {})" @click="() => (closeOnClickOutside && closable ? hide() : {})"
/> />
<div <div class="modal-container experimental-styles-within" :class="{ shown: visible }">
class="modal-container experimental-styles-within"
:class="{ shown: visible }"
:style="{
'--_max-width': maxWidth,
'--_width': width,
}"
>
<div <div
ref="modalBodyRef" ref="modalBodyRef"
role="dialog" role="dialog"
@@ -223,6 +213,7 @@ const closeLabel = computed(() => formatMessage(commonMessages.closeButton))
const open = ref(false) const open = ref(false)
const visible = ref(false) const visible = ref(false)
const stackDepth = ref(0)
const modalBodyRef = ref<HTMLElement | null>(null) const modalBodyRef = ref<HTMLElement | null>(null)
let previousFocusEl: Element | null = null let previousFocusEl: Element | null = null
@@ -240,6 +231,7 @@ function getFocusableElements(): HTMLElement[] {
function show(event?: MouseEvent) { function show(event?: MouseEvent) {
props.onShow?.() props.onShow?.()
const wasEmpty = modalStackSize() === 0 const wasEmpty = modalStackSize() === 0
stackDepth.value = modalStackSize()
open.value = true open.value = true
previousFocusEl = document.activeElement previousFocusEl = document.activeElement
pushModal() pushModal()
@@ -251,8 +243,8 @@ function show(event?: MouseEvent) {
if (event) { if (event) {
updateMousePosition(event) updateMousePosition(event)
} else { } else {
mouseX.value = window.innerWidth / 2 mouseX.value = Math.round(window.innerWidth / 2)
mouseY.value = window.innerHeight / 2 mouseY.value = Math.round(window.innerHeight / 2)
} }
setTimeout(() => { setTimeout(() => {
visible.value = true visible.value = true
@@ -293,8 +285,17 @@ defineExpose({
checkScrollState, checkScrollState,
}) })
const mouseX = ref(-1) const mouseX = ref(0)
const mouseY = ref(-1) const mouseY = ref(0)
const stackZBase = computed(() => stackDepth.value * 10)
const stackOverlayZ = computed(() => stackZBase.value + 19)
const stackTauriZ = computed(() => stackZBase.value + 20)
const stackContainerZ = computed(() => stackZBase.value + 21)
const resolvedMaxWidth = computed(() => props.maxWidth ?? '60rem')
const resolvedWidth = computed(() => props.width ?? 'fit-content')
const mouseXOffset = computed(() => `calc((-50vw + ${mouseX.value}px) / 16)`)
const mouseYOffset = computed(() => `calc((-50vh + ${mouseY.value}px) / 16)`)
function updateMousePosition(event: { clientX: number; clientY: number }) { function updateMousePosition(event: { clientX: number; clientY: number }) {
mouseX.value = event.clientX mouseX.value = event.clientX
@@ -317,8 +318,8 @@ function handleWindowKeyDown(event: KeyboardEvent) {
if (props.closeOnEsc && event.key === 'Escape' && props.closable) { if (props.closeOnEsc && event.key === 'Escape' && props.closable) {
if (!isTopmostModal()) return if (!isTopmostModal()) return
hide() hide()
mouseX.value = window.innerWidth / 2 mouseX.value = Math.round(window.innerWidth / 2)
mouseY.value = window.innerHeight / 2 mouseY.value = Math.round(window.innerHeight / 2)
} }
} }
@@ -353,7 +354,7 @@ function handleKeyDown(event: KeyboardEvent) {
left: 0; left: 0;
width: 100%; width: 100%;
height: 100px; height: 100px;
z-index: 20; z-index: v-bind(stackTauriZ);
&.shown { &.shown {
opacity: 1; opacity: 1;
@@ -364,7 +365,7 @@ function handleKeyDown(event: KeyboardEvent) {
.modal-overlay { .modal-overlay {
position: fixed; position: fixed;
inset: -5rem; inset: -5rem;
z-index: 19; z-index: v-bind(stackOverlayZ);
opacity: 0; opacity: 0;
transition: all 0.2s ease-out; transition: all 0.2s ease-out;
//transform: translate( //transform: translate(
@@ -419,13 +420,10 @@ function handleKeyDown(event: KeyboardEvent) {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
z-index: 21; z-index: v-bind(stackContainerZ);
visibility: hidden; visibility: hidden;
pointer-events: none; pointer-events: none;
transform: translate( transform: translate(v-bind(mouseXOffset), v-bind(mouseYOffset));
calc((-50vw + var(--_mouse-x, 50vw) * 1px) / 16),
calc((-50vh + var(--_mouse-y, 50vh) * 1px) / 16)
);
transition: all 0.2s ease-out; transition: all 0.2s ease-out;
&.shown { &.shown {
@@ -443,10 +441,10 @@ function handleKeyDown(event: KeyboardEvent) {
position: fixed; position: fixed;
box-shadow: 4px 4px 26px 10px rgba(0, 0, 0, 0.08); box-shadow: 4px 4px 26px 10px rgba(0, 0, 0, 0.08);
max-height: calc(100% - 2 * var(--gap-lg)); max-height: calc(100% - 2 * var(--gap-lg));
max-width: min(var(--_max-width, 60rem), calc(100% - 2 * var(--gap-lg))); max-width: min(v-bind(resolvedMaxWidth), calc(100% - 2 * var(--gap-lg)));
overflow-y: hidden; overflow-y: hidden;
overflow-x: hidden; overflow-x: hidden;
width: var(--_width, fit-content); width: v-bind(resolvedWidth);
pointer-events: auto; pointer-events: auto;
scale: 0.97; scale: 0.97;

View File

@@ -1,6 +1,7 @@
<script setup> <script setup>
import { import {
ClipboardCopyIcon, ClipboardCopyIcon,
ExternalIcon,
GlobeIcon, GlobeIcon,
MailIcon, MailIcon,
MastodonIcon, MastodonIcon,
@@ -192,6 +193,12 @@ defineExpose({
<ClipboardCopyIcon class="h-5 w-5" aria-hidden="true" /> <ClipboardCopyIcon class="h-5 w-5" aria-hidden="true" />
</div> </div>
</button> </button>
<ButtonStyled v-if="link">
<a :href="url" target="_blank" rel="noopener noreferrer" aria-label="Open in new tab">
<ExternalIcon aria-hidden="true" />
Open in new tab
</a>
</ButtonStyled>
<div v-if="socialButtons" class="flex flex-row gap-2"> <div v-if="socialButtons" class="flex flex-row gap-2">
<Button v-if="canShare" v-tooltip="'Share'" aria-label="Share" icon-only @click="share"> <Button v-if="canShare" v-tooltip="'Share'" aria-label="Share" icon-only @click="share">
<ShareIcon aria-hidden="true" /> <ShareIcon aria-hidden="true" />

View File

@@ -849,6 +849,12 @@ async function confirmResetToOnboarding() {
try { try {
isResettingToOnboarding.value = true isResettingToOnboarding.value = true
await client.archon.servers_v1.resetToOnboarding(serverId, worldId.value) await client.archon.servers_v1.resetToOnboarding(serverId, worldId.value)
modrinthServersConsole.clear()
try {
await client.kyros.logs_v1.clear()
} catch (error) {
console.error('Failed to clear server logs:', error)
}
server.value.flows = { intro: true } server.value.flows = { intro: true }
await Promise.all([ await Promise.all([
queryClient.invalidateQueries({ queryKey: ['servers', 'detail', serverId] }), queryClient.invalidateQueries({ queryKey: ['servers', 'detail', serverId] }),

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="relative flex select-none flex-col gap-6" data-pyro-server-manager-root> <div class="relative flex select-none flex-col gap-6" data-pyro-server-manager-root>
<div class="flex flex-col-reverse gap-6 md:flex-col"> <div class="flex flex-col gap-6">
<ServerManageStats <ServerManageStats
:data="!isWsAuthIncorrect ? stats : undefined" :data="!isWsAuthIncorrect ? stats : undefined"
:loading="isWsAuthIncorrect" :loading="isWsAuthIncorrect"