diff --git a/src/client/components/Dashboard.tsx b/src/client/components/Dashboard.tsx index 72349f7..63d9aaf 100644 --- a/src/client/components/Dashboard.tsx +++ b/src/client/components/Dashboard.tsx @@ -14,7 +14,6 @@ import { import { AppDetail } from './AppDetail' import { AppSelector } from './AppSelector' import { DashboardLanding } from './DashboardLanding' -import { Modal } from './modal' import { SettingsPage } from './SettingsPage' import { Sidebar } from './Sidebar' @@ -55,7 +54,6 @@ export function Dashboard({ render }: { render: () => void }) { {!isNarrow && } - ) } diff --git a/src/client/components/modal.tsx b/src/client/components/modal.tsx index d513285..fb5c833 100644 --- a/src/client/components/modal.tsx +++ b/src/client/components/modal.tsx @@ -1,19 +1,21 @@ import type { Child } from 'hono/jsx' +import { render } from 'hono/jsx/dom' import { define } from '@because/forge' import { theme } from '../themes' let modalTitle: string | null = null let modalContent: (() => Child) | null = null -let renderFn: (() => void) | null = null -export const initModal = (render: () => void) => { - renderFn = render +const root = document.getElementById('modal')! + +const renderModal = () => { + render(, root) } export const openModal = (title: string, content: () => Child) => { modalTitle = title modalContent = content - renderFn?.() + renderModal() requestAnimationFrame(() => { document.querySelector('[data-modal-body] input')?.focus() }) @@ -22,12 +24,10 @@ export const openModal = (title: string, content: () => Child) => { export const closeModal = () => { modalTitle = null modalContent = null - renderFn?.() + renderModal() } -export const rerenderModal = () => { - renderFn?.() -} +export { renderModal } // ESC key handler document.addEventListener('keydown', (e) => { diff --git a/src/client/index.tsx b/src/client/index.tsx index a8bec33..a4460a7 100644 --- a/src/client/index.tsx +++ b/src/client/index.tsx @@ -1,6 +1,5 @@ import { render as renderApp } from 'hono/jsx/dom' import { Dashboard } from './components' -import { initModal } from './components/modal' import { initRouter, navigate } from './router' import { apps, dashboardTab, getSelectedTab, selectedApp, setApps, setIsNarrow } from './state' import { initToolIframes, updateToolIframes } from './tool-iframes' @@ -21,7 +20,6 @@ const render = () => { } // Initialize render functions -initModal(render) initUpdate(render) initToolIframes() diff --git a/src/client/modals/DeleteApp.tsx b/src/client/modals/DeleteApp.tsx index d07de9f..218b6c7 100644 --- a/src/client/modals/DeleteApp.tsx +++ b/src/client/modals/DeleteApp.tsx @@ -1,5 +1,5 @@ import type { App } from '../../shared/types' -import { closeModal, openModal, rerenderModal } from '../components/modal' +import { closeModal, openModal, renderModal } from '../components/modal' import { navigate } from '../router' import { selectedApp } from '../state' import { Button, Form, FormActions, FormError, FormField, FormInput, FormLabel } from '../styles' @@ -17,13 +17,13 @@ async function deleteApp(input: HTMLInputElement) { if (value !== expected) { deleteAppError = `Type "${expected}" to confirm` - rerenderModal() + renderModal() return } deleteAppDeleting = true deleteAppError = '' - rerenderModal() + renderModal() try { const res = await fetch(`/api/sync/apps/${deleteAppTarget.name}`, { @@ -41,7 +41,7 @@ async function deleteApp(input: HTMLInputElement) { } catch (err) { deleteAppError = err instanceof Error ? err.message : 'Failed to delete app' deleteAppDeleting = false - rerenderModal() + renderModal() } } diff --git a/src/client/modals/NewApp.tsx b/src/client/modals/NewApp.tsx index 94f51d5..e48e654 100644 --- a/src/client/modals/NewApp.tsx +++ b/src/client/modals/NewApp.tsx @@ -1,4 +1,4 @@ -import { closeModal, openModal, rerenderModal } from '../components/modal' +import { closeModal, openModal, renderModal } from '../components/modal' import { navigate } from '../router' import { apps } from '../state' import { Button, Form, FormActions, FormCheckbox, FormCheckboxField, FormCheckboxLabel, FormError, FormField, FormInput, FormLabel, FormSelect } from '../styles' @@ -16,25 +16,25 @@ async function createNewApp() { if (!name) { newAppError = 'App name is required' - rerenderModal() + renderModal() return } if (!/^[a-z][a-z0-9-]*$/.test(name)) { newAppError = 'Name must start with a letter and contain only lowercase letters, numbers, and hyphens' - rerenderModal() + renderModal() return } if (apps.some(a => a.name === name)) { newAppError = 'An app with this name already exists' - rerenderModal() + renderModal() return } newAppCreating = true newAppError = '' - rerenderModal() + renderModal() try { const res = await fetch('/api/apps', { @@ -55,7 +55,7 @@ async function createNewApp() { } catch (err) { newAppError = err instanceof Error ? err.message : 'Failed to create app' newAppCreating = false - rerenderModal() + renderModal() } } @@ -105,7 +105,7 @@ export function openNewAppModal() { checked={newAppTool} onChange={(e: Event) => { newAppTool = (e.target as HTMLInputElement).checked - rerenderModal() + renderModal() }} /> Tool diff --git a/src/client/modals/RenameApp.tsx b/src/client/modals/RenameApp.tsx index 53c0101..3e8c2ca 100644 --- a/src/client/modals/RenameApp.tsx +++ b/src/client/modals/RenameApp.tsx @@ -1,5 +1,5 @@ import type { App } from '../../shared/types' -import { closeModal, openModal, rerenderModal } from '../components/modal' +import { closeModal, openModal, renderModal } from '../components/modal' import { navigate } from '../router' import { apps } from '../state' import { Button, Form, FormActions, FormError, FormField, FormInput, FormLabel } from '../styles' @@ -15,13 +15,13 @@ async function doRenameApp(input: HTMLInputElement) { if (!newName) { renameAppError = 'App name is required' - rerenderModal() + renderModal() return } if (!/^[a-z][a-z0-9-]*$/.test(newName)) { renameAppError = 'Name must start with a letter and contain only lowercase letters, numbers, and hyphens' - rerenderModal() + renderModal() return } @@ -32,13 +32,13 @@ async function doRenameApp(input: HTMLInputElement) { if (apps.some(a => a.name === newName)) { renameAppError = 'An app with this name already exists' - rerenderModal() + renderModal() return } renameAppRenaming = true renameAppError = '' - rerenderModal() + renderModal() try { const res = await fetch(`/api/apps/${renameAppTarget.name}/rename`, { @@ -65,7 +65,7 @@ async function doRenameApp(input: HTMLInputElement) { } catch (err) { renameAppError = err instanceof Error ? err.message : 'Failed to rename app' renameAppRenaming = false - rerenderModal() + renderModal() } } diff --git a/src/server/shell.tsx b/src/server/shell.tsx index daf3879..afebae8 100644 --- a/src/server/shell.tsx +++ b/src/server/shell.tsx @@ -9,6 +9,7 @@ export const Shell = () => (
+