The inline-expand version (within the bottom sheet) was awkward — the sheet's content shifted around and the destructive button visually inherited the same layout as Save. Switched to a centered overlay modal teleported to <body>: - Backdrop with semi-transparent dark + subtle blur, click-to-cancel. - Card scales up slightly on enter, fades out on leave. - Two-button row: Cancel (neutral) and Yes, remove (red). - alertdialog role for screen readers. The Remove button stays in the sheet so the entry point is unchanged; only the confirmation surface moves out of the sheet's flow. Tests updated for <Teleport>: HomeView.test.ts queries document directly for the modal (it lives outside the wrapper's tree). New case for backdrop-click cancel. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -226,39 +226,49 @@
|
||||
{{ saving ? 'Saving…' : 'Save' }}
|
||||
</BaseButton>
|
||||
|
||||
<template v-if="!removeConfirmOpen">
|
||||
<button
|
||||
type="button"
|
||||
class="home-view__remove"
|
||||
@click="removeConfirmOpen = true"
|
||||
>Remove this frame</button>
|
||||
</template>
|
||||
|
||||
<div v-else class="home-view__remove-confirm" role="alertdialog" aria-labelledby="remove-confirm-title">
|
||||
<p class="home-view__remove-confirm-title" id="remove-confirm-title">
|
||||
Remove this frame?
|
||||
</p>
|
||||
<p class="home-view__remove-confirm-body">
|
||||
Use this if you’re selling or giving away the frame. It deletes
|
||||
this frame from your account and unlinks it from your photos so the
|
||||
next owner can claim it fresh. This can’t be undone.
|
||||
</p>
|
||||
<div class="home-view__remove-confirm-actions">
|
||||
<button
|
||||
type="button"
|
||||
class="home-view__remove-cancel"
|
||||
:disabled="removing"
|
||||
@click="removeConfirmOpen = false"
|
||||
>Cancel</button>
|
||||
<button
|
||||
type="button"
|
||||
class="home-view__remove-confirm-btn"
|
||||
:disabled="removing"
|
||||
@click="performRemove"
|
||||
>{{ removing ? 'Removing…' : 'Yes, remove' }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="home-view__remove"
|
||||
@click="removeConfirmOpen = true"
|
||||
>Remove this frame</button>
|
||||
</BaseBottomSheet>
|
||||
|
||||
<Teleport to="body">
|
||||
<Transition name="home-view__remove-modal">
|
||||
<div
|
||||
v-if="removeConfirmOpen"
|
||||
class="home-view__remove-modal"
|
||||
role="alertdialog"
|
||||
aria-labelledby="remove-confirm-title"
|
||||
@click.self="removeConfirmOpen = false"
|
||||
>
|
||||
<div class="home-view__remove-modal-card">
|
||||
<p class="home-view__remove-confirm-title" id="remove-confirm-title">
|
||||
Remove this frame?
|
||||
</p>
|
||||
<p class="home-view__remove-confirm-body">
|
||||
Use this if you’re selling or giving away the frame. It deletes
|
||||
this frame from your account and unlinks it from your photos so
|
||||
the next owner can claim it fresh. This can’t be undone.
|
||||
</p>
|
||||
<div class="home-view__remove-confirm-actions">
|
||||
<button
|
||||
type="button"
|
||||
class="home-view__remove-cancel"
|
||||
:disabled="removing"
|
||||
@click="removeConfirmOpen = false"
|
||||
>Cancel</button>
|
||||
<button
|
||||
type="button"
|
||||
class="home-view__remove-confirm-btn"
|
||||
:disabled="removing"
|
||||
@click="performRemove"
|
||||
>{{ removing ? 'Removing…' : 'Yes, remove' }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -1048,12 +1058,41 @@ async function saveSettings() {
|
||||
}
|
||||
}
|
||||
|
||||
&__remove-confirm {
|
||||
margin-top: var(--space-5);
|
||||
padding: var(--space-3);
|
||||
border: 1.5px solid var(--color-danger, #c0392b);
|
||||
&__remove-modal {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: var(--space-4);
|
||||
background: rgba(20, 14, 8, 0.55);
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
|
||||
&__remove-modal-card {
|
||||
width: 100%;
|
||||
max-width: 360px;
|
||||
padding: var(--space-4);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--color-surface);
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
// Transition: card scales up subtly + fades; backdrop fades.
|
||||
&__remove-modal-enter-active,
|
||||
&__remove-modal-leave-active {
|
||||
transition: opacity var(--duration-fast) ease;
|
||||
}
|
||||
&__remove-modal-enter-active .home-view__remove-modal-card,
|
||||
&__remove-modal-leave-active .home-view__remove-modal-card {
|
||||
transition: transform var(--duration-fast) ease;
|
||||
}
|
||||
&__remove-modal-enter-from,
|
||||
&__remove-modal-leave-to { opacity: 0; }
|
||||
&__remove-modal-enter-from .home-view__remove-modal-card,
|
||||
&__remove-modal-leave-to .home-view__remove-modal-card {
|
||||
transform: scale(0.96);
|
||||
}
|
||||
|
||||
&__remove-confirm-title {
|
||||
|
||||
Reference in New Issue
Block a user