refactor(web): migrate remaining route-inline modals to shared Modal primitive (TASK-2083) (#890)

This commit is contained in:
xarmian
2026-07-09 20:37:10 -04:00
committed by GitHub
parent be8fdf8d06
commit 55c8eff0a6
2 changed files with 37 additions and 69 deletions
@@ -19,6 +19,7 @@
import { toastStore } from '$lib/stores/toast.svelte';
import ShareDialog from '$lib/components/ShareDialog.svelte';
import EditCollectionModal from '$lib/components/collections/EditCollectionModal.svelte';
import Modal from '$lib/components/common/Modal.svelte';
import { collectionStore } from '$lib/stores/collections.svelte';
import { uiStore } from '$lib/stores/ui.svelte';
import { titleStore } from '$lib/stores/title.svelte';
@@ -2182,16 +2183,20 @@
/>
{/if}
{#if showLeaveDialog}
<!-- Leave guard (TASK-1676): an in-app navigation was intercepted
because a lane has an unsaved draft card. -->
<div
class="leave-overlay"
role="presentation"
onclick={(e) => { if (e.target === e.currentTarget) leaveStay(); }}
onkeydown={(e) => { if (e.key === 'Escape') leaveStay(); }}
>
<div class="leave-dialog" role="dialog" aria-modal="true" aria-label="Unsaved card" tabindex="-1">
<!-- Leave guard (TASK-1676): an in-app navigation was intercepted because a lane
has an unsaved draft card. Backdrop/Escape dismiss maps to "Stay" (the safe,
non-destructive default) via the shared Modal primitive (TASK-2083). -->
<Modal
open={showLeaveDialog}
onclose={leaveStay}
ariaLabel="Unsaved card"
maxWidth="360px"
placement="center"
--modal-bg="var(--bg-primary)"
--modal-shadow="var(--shadow-lg, 0 10px 30px rgba(0, 0, 0, 0.3))"
>
{#if showLeaveDialog}
<div class="leave-dialog">
<h3 class="leave-title">Unsaved card</h3>
<p class="leave-body">You have an unsaved card. Save it before leaving?</p>
<div class="leave-actions">
@@ -2200,28 +2205,14 @@
<button class="leave-save" disabled={savingDrafts} onclick={leaveSaveAll}>Save</button>
</div>
</div>
</div>
{/if}
{/if}
</Modal>
<style>
.leave-overlay {
position: fixed;
inset: 0;
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.45);
padding: var(--space-4);
}
/* Surface/backdrop/Escape come from the shared <Modal> primitive (TASK-2083);
this wrapper just restores the inner padding. */
.leave-dialog {
width: 100%;
max-width: 360px;
padding: var(--space-4);
background: var(--bg-primary);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-lg, 0 10px 30px rgba(0, 0, 0, 0.3));
}
.leave-title {
margin: 0 0 var(--space-2);
@@ -1,6 +1,7 @@
<script lang="ts">
import { onMount } from 'svelte';
import { api } from '$lib/api/client';
import Modal from '$lib/components/common/Modal.svelte';
import type { ConnectedApp, Workspace } from '$lib/types';
// Connected Apps page (TASK-954). Lists every active OAuth grant
@@ -258,19 +259,6 @@
}
}
function onBackdropClick(e: MouseEvent) {
if (e.target === e.currentTarget) closeConfirm();
}
$effect(() => {
if (!confirmTarget) return;
function onKey(e: KeyboardEvent) {
if (e.key === 'Escape') closeConfirm();
}
window.addEventListener('keydown', onKey);
return () => window.removeEventListener('keydown', onKey);
});
onMount(() => {
loadApps();
});
@@ -588,13 +576,18 @@
{/if}
</div>
{#if confirmTarget}
<div
class="modal-backdrop"
role="presentation"
onclick={onBackdropClick}
>
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="revoke-title">
<Modal
open={!!confirmTarget}
onclose={closeConfirm}
labelledby="revoke-title"
maxWidth="420px"
placement="center"
--modal-bg="var(--bg-primary)"
--modal-radius="var(--radius)"
--modal-shadow="0 20px 60px rgba(0, 0, 0, 0.3)"
>
{#if confirmTarget}
<div class="revoke-modal">
<h3 id="revoke-title" class="modal-title">Revoke {confirmTarget.client_name}?</h3>
<p class="modal-body">
The app will lose access immediately. This can&rsquo;t be undone.
@@ -609,8 +602,8 @@
</button>
</div>
</div>
</div>
{/if}
{/if}
</Modal>
<style>
.page {
@@ -933,29 +926,13 @@
border-color: #ef4444;
}
/* Modal */
.modal-backdrop {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
padding: var(--space-4);
z-index: 100;
}
.modal {
background: var(--bg-primary);
border: 1px solid var(--border);
border-radius: var(--radius);
/* Modal — surface/backdrop/Escape come from the shared <Modal> primitive
(TASK-2083); this wrapper just restores the inner padding + column layout. */
.revoke-modal {
padding: var(--space-5);
max-width: 420px;
width: 100%;
display: flex;
flex-direction: column;
gap: var(--space-3);
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}
.modal-title {