From 2464389e2ba5758e14365436a9ecd9b6e4565b12 Mon Sep 17 00:00:00 2001 From: Coracle-Bot Date: Sat, 12 Sep 2026 03:44:06 +0000 Subject: [PATCH] Keep modal state in a plain module instead of a rune file (#514) --- eslint.config.js | 2 +- src/app/components/AppContainer.svelte | 2 +- src/app/components/ModalContainer.svelte | 3 +-- src/app/components/PrimaryNav.svelte | 3 +-- src/app/modal.svelte.ts | 31 --------------------- src/app/modal.ts | 34 ++++++++++++++++++++---- src/routes/join/+page.svelte | 2 +- src/routes/spaces/[relay]/+layout.svelte | 3 +-- 8 files changed, 35 insertions(+), 45 deletions(-) delete mode 100644 src/app/modal.svelte.ts diff --git a/eslint.config.js b/eslint.config.js index 5584a937..52c52e7e 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -20,7 +20,7 @@ export default [ }, }, { - files: ["**/*.svelte", "**/*.svelte.ts"], + files: ["**/*.svelte"], languageOptions: { parserOptions: { parser: ts.parser, diff --git a/src/app/components/AppContainer.svelte b/src/app/components/AppContainer.svelte index d76ed1e5..a90a8ae1 100644 --- a/src/app/components/AppContainer.svelte +++ b/src/app/components/AppContainer.svelte @@ -7,7 +7,7 @@ import SpeechBanner from "@app/components/SpeechBanner.svelte" import PrimaryNav from "@app/components/PrimaryNav.svelte" import {app} from "@app/core" - import {getModal} from "@app/modal.svelte" + import {getModal} from "@app/modal" type Props = { children: Snippet diff --git a/src/app/components/ModalContainer.svelte b/src/app/components/ModalContainer.svelte index e1d8b1e8..e6110af2 100644 --- a/src/app/components/ModalContainer.svelte +++ b/src/app/components/ModalContainer.svelte @@ -2,8 +2,7 @@ import {mount, unmount, untrack} from "svelte" import Drawer from "@lib/components/Drawer.svelte" import Dialog from "@lib/components/Dialog.svelte" - import {popModal} from "@app/modal" - import {getModal, getModalStack} from "@app/modal.svelte" + import {getModal, getModalStack, popModal} from "@app/modal" const closeModal = () => { const modal = getModal() diff --git a/src/app/components/PrimaryNav.svelte b/src/app/components/PrimaryNav.svelte index 1ca4b7a4..ad966ca3 100644 --- a/src/app/components/PrimaryNav.svelte +++ b/src/app/components/PrimaryNav.svelte @@ -15,8 +15,7 @@ import Search from "@app/components/Search.svelte" import SpaceMenuDrawer from "@app/components/SpaceMenuDrawer.svelte" import {PLATFORM_RELAYS} from "@app/env" - import {popModal, pushModal} from "@app/modal" - import {getModal} from "@app/modal.svelte" + import {getModal, popModal, pushModal} from "@app/modal" import {notifications} from "@app/notifications" import {userSpaceUrls} from "@app/rooms" import {goToChat, lastSpaceUrl, makeSpacePath} from "@app/routes" diff --git a/src/app/modal.svelte.ts b/src/app/modal.svelte.ts deleted file mode 100644 index 57e01a63..00000000 --- a/src/app/modal.svelte.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type {Component} from "svelte" -import {last} from "@welshman/lib" -import {page} from "$app/state" -import type {DialogSize} from "@lib/components/Dialog.svelte" - -export type ModalOptions = { - drawer?: boolean - nested?: boolean - noEscape?: boolean - fullscreen?: boolean - size?: DialogSize - replaceState?: boolean - path?: string -} - -export type Modal = { - id: string - component: Component - props: Record - options: ModalOptions -} - -export const modals = $state>({}) - -// Open modal ids live in SvelteKit's page state (shallow routing): each modal owns a history entry -// without a navigation, and any `goto` that doesn't pass `state` along closes them. -const modalStack = $derived((page.state.modals ?? []).map(id => modals[id]).filter(Boolean)) - -export const getModalStack = () => modalStack - -export const getModal = () => last(modalStack) diff --git a/src/app/modal.ts b/src/app/modal.ts index f00b7b15..cf4bd908 100644 --- a/src/app/modal.ts +++ b/src/app/modal.ts @@ -1,23 +1,47 @@ import type {Component} from "svelte" -import {randomId, Emitter} from "@welshman/lib" +import {randomId, last, Emitter} from "@welshman/lib" import {goto, pushState, replaceState} from "$app/navigation" import {page} from "$app/state" -import {modals, type ModalOptions} from "@app/modal.svelte" +import type {DialogSize} from "@lib/components/Dialog.svelte" + +export type ModalOptions = { + drawer?: boolean + nested?: boolean + noEscape?: boolean + fullscreen?: boolean + size?: DialogSize + replaceState?: boolean + path?: string +} + +export type Modal = { + id: string + component: Component + props: Record + options: ModalOptions +} export const emitter = new Emitter() +const modals: Record = {} + +// Open modal ids live in SvelteKit page state (shallow routing): each modal owns a history entry +// without a navigation, and any `goto` that does not pass `state` along closes them. +export const getModalStack = () => (page.state.modals ?? []).map(id => modals[id]).filter(Boolean) + +export const getModal = () => last(getModalStack()) + export type NavigateOptions = Parameters[1] & {keepModal?: boolean} // An open modal owns the current history entry, so a navigation that drops it takes that entry over export const navigate = (path: string, {keepModal, ...options}: NavigateOptions = {}) => { const ids = page.state.modals ?? [] - const modalIsOpen = ids.length > 0 - if (keepModal && modalIsOpen) { + if (keepModal && ids.length > 0) { return goto(path, {...options, state: {modals: ids}, replaceState: true}) } - return goto(path, {...options, replaceState: options.replaceState || modalIsOpen}) + return goto(path, {...options, replaceState: options.replaceState || ids.length > 0}) } export const pushModal = ( diff --git a/src/routes/join/+page.svelte b/src/routes/join/+page.svelte index 91f196e6..526e7b35 100644 --- a/src/routes/join/+page.svelte +++ b/src/routes/join/+page.svelte @@ -3,7 +3,7 @@ import Dialog from "@lib/components/Dialog.svelte" import SpaceInviteAccept from "@app/components/SpaceInviteAccept.svelte" import {goToHome} from "@app/routes" - import {getModal} from "@app/modal.svelte" + import {getModal} from "@app/modal" const children = { component: SpaceInviteAccept, diff --git a/src/routes/spaces/[relay]/+layout.svelte b/src/routes/spaces/[relay]/+layout.svelte index 3c809860..661808bd 100644 --- a/src/routes/spaces/[relay]/+layout.svelte +++ b/src/routes/spaces/[relay]/+layout.svelte @@ -21,8 +21,7 @@ import {deriveRelayAuthError} from "@app/access" import {relays, roomLists, user} from "@app/core" import {userSpaceUrls} from "@app/rooms" - import {pushModal} from "@app/modal" - import {getModal} from "@app/modal.svelte" + import {getModal, pushModal} from "@app/modal" import {relaysPendingTrust} from "@app/policies" import {decodeRelay} from "@app/relays" import {makeSpacePath} from "@app/routes"