mirror of
https://github.com/sst/opencode.git
synced 2025-12-23 10:11:41 +00:00
fix dialog root complexity
This commit is contained in:
parent
f3e64cfb19
commit
56452d886d
4 changed files with 139 additions and 105 deletions
|
|
@ -12,7 +12,7 @@ import { GlobalSDKProvider } from "@/context/global-sdk"
|
|||
import { TerminalProvider } from "@/context/terminal"
|
||||
import { PromptProvider } from "@/context/prompt"
|
||||
import { NotificationProvider } from "@/context/notification"
|
||||
import { DialogProvider, DialogRoot } from "@opencode-ai/ui/context/dialog"
|
||||
import { DialogProvider } from "@opencode-ai/ui/context/dialog"
|
||||
import { CommandProvider } from "@/context/command"
|
||||
import Layout from "@/pages/layout"
|
||||
import Home from "@/pages/home"
|
||||
|
|
@ -36,46 +36,46 @@ const url =
|
|||
|
||||
export function App() {
|
||||
return (
|
||||
<MarkedProvider>
|
||||
<DiffComponentProvider component={Diff}>
|
||||
<GlobalSDKProvider url={url}>
|
||||
<GlobalSyncProvider>
|
||||
<LayoutProvider>
|
||||
<NotificationProvider>
|
||||
<MetaProvider>
|
||||
<Font />
|
||||
<Router
|
||||
root={(props) => (
|
||||
<DialogProvider>
|
||||
<DialogProvider>
|
||||
<MarkedProvider>
|
||||
<DiffComponentProvider component={Diff}>
|
||||
<GlobalSDKProvider url={url}>
|
||||
<GlobalSyncProvider>
|
||||
<LayoutProvider>
|
||||
<NotificationProvider>
|
||||
<MetaProvider>
|
||||
<Font />
|
||||
<Router
|
||||
root={(props) => (
|
||||
<CommandProvider>
|
||||
<Layout>{props.children}</Layout>
|
||||
</CommandProvider>
|
||||
</DialogProvider>
|
||||
)}
|
||||
>
|
||||
<Route path="/" component={Home} />
|
||||
<Route path="/:dir" component={DirectoryLayout}>
|
||||
<Route path="/" component={() => <Navigate href="session" />} />
|
||||
<Route
|
||||
path="/session/:id?"
|
||||
component={(p) => (
|
||||
<Show when={p.params.id || true} keyed>
|
||||
<TerminalProvider>
|
||||
<PromptProvider>
|
||||
<Session />
|
||||
</PromptProvider>
|
||||
</TerminalProvider>
|
||||
</Show>
|
||||
)}
|
||||
/>
|
||||
</Route>
|
||||
</Router>
|
||||
</MetaProvider>
|
||||
</NotificationProvider>
|
||||
</LayoutProvider>
|
||||
</GlobalSyncProvider>
|
||||
</GlobalSDKProvider>
|
||||
</DiffComponentProvider>
|
||||
</MarkedProvider>
|
||||
)}
|
||||
>
|
||||
<Route path="/" component={Home} />
|
||||
<Route path="/:dir" component={DirectoryLayout}>
|
||||
<Route path="/" component={() => <Navigate href="session" />} />
|
||||
<Route
|
||||
path="/session/:id?"
|
||||
component={(p) => (
|
||||
<Show when={p.params.id || true} keyed>
|
||||
<TerminalProvider>
|
||||
<PromptProvider>
|
||||
<Session />
|
||||
</PromptProvider>
|
||||
</TerminalProvider>
|
||||
</Show>
|
||||
)}
|
||||
/>
|
||||
</Route>
|
||||
</Router>
|
||||
</MetaProvider>
|
||||
</NotificationProvider>
|
||||
</LayoutProvider>
|
||||
</GlobalSyncProvider>
|
||||
</GlobalSDKProvider>
|
||||
</DiffComponentProvider>
|
||||
</MarkedProvider>
|
||||
</DialogProvider>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import { createMemo } from "solid-js"
|
|||
export const popularProviders = ["opencode", "anthropic", "github-copilot", "openai", "google", "openrouter", "vercel"]
|
||||
|
||||
export function useProviders() {
|
||||
const params = useParams()
|
||||
const globalSync = useGlobalSync()
|
||||
const params = useParams()
|
||||
const currentDirectory = createMemo(() => base64Decode(params.dir ?? ""))
|
||||
const providers = createMemo(() => {
|
||||
if (currentDirectory()) {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import { LocalProvider } from "@/context/local"
|
|||
import { base64Decode } from "@opencode-ai/util/encode"
|
||||
import { DataProvider } from "@opencode-ai/ui/context"
|
||||
import { iife } from "@opencode-ai/util/iife"
|
||||
import { DialogRoot } from "@opencode-ai/ui/context/dialog"
|
||||
|
||||
export default function Layout(props: ParentProps) {
|
||||
const params = useParams()
|
||||
|
|
@ -21,9 +20,7 @@ export default function Layout(props: ParentProps) {
|
|||
const sync = useSync()
|
||||
return (
|
||||
<DataProvider data={sync.data} directory={directory()}>
|
||||
<LocalProvider>
|
||||
<DialogRoot>{props.children}</DialogRoot>
|
||||
</LocalProvider>
|
||||
<LocalProvider>{props.children}</LocalProvider>
|
||||
</DataProvider>
|
||||
)
|
||||
})}
|
||||
|
|
|
|||
|
|
@ -1,79 +1,116 @@
|
|||
import { For, Show, type JSX } from "solid-js"
|
||||
import { createStore } from "solid-js/store"
|
||||
import { createSimpleContext } from "@opencode-ai/ui/context"
|
||||
|
||||
type DialogElement = JSX.Element | (() => JSX.Element)
|
||||
|
||||
export const { use: useDialog, provider: DialogProvider } = createSimpleContext({
|
||||
name: "Dialog",
|
||||
init: () => {
|
||||
const [store, setStore] = createStore({
|
||||
stack: [] as {
|
||||
element: DialogElement
|
||||
onClose?: () => void
|
||||
}[],
|
||||
})
|
||||
|
||||
return {
|
||||
get stack() {
|
||||
return store.stack
|
||||
},
|
||||
push(element: DialogElement, onClose?: () => void) {
|
||||
setStore("stack", (s) => [...s, { element, onClose }])
|
||||
},
|
||||
pop() {
|
||||
const current = store.stack.at(-1)
|
||||
current?.onClose?.()
|
||||
setStore("stack", store.stack.slice(0, -1))
|
||||
},
|
||||
replace(element: DialogElement, onClose?: () => void) {
|
||||
for (const item of store.stack) {
|
||||
item.onClose?.()
|
||||
}
|
||||
setStore("stack", [{ element, onClose }])
|
||||
},
|
||||
clear() {
|
||||
for (const item of store.stack) {
|
||||
item.onClose?.()
|
||||
}
|
||||
setStore("stack", [])
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
import {
|
||||
createContext,
|
||||
createMemo,
|
||||
createSignal,
|
||||
getOwner,
|
||||
Owner,
|
||||
ParentProps,
|
||||
runWithOwner,
|
||||
Show,
|
||||
useContext,
|
||||
type JSX,
|
||||
} from "solid-js"
|
||||
import { Dialog as Kobalte } from "@kobalte/core/dialog"
|
||||
|
||||
export function DialogRoot(props: { children?: JSX.Element }) {
|
||||
const dialog = useDialog()
|
||||
type DialogElement = () => JSX.Element
|
||||
|
||||
const Context = createContext<ReturnType<typeof init>>()
|
||||
|
||||
function init() {
|
||||
const [store, setStore] = createSignal<
|
||||
{
|
||||
element: DialogElement
|
||||
onClose?: () => void
|
||||
owner: Owner
|
||||
}[]
|
||||
>([])
|
||||
|
||||
return {
|
||||
get stack() {
|
||||
return store()
|
||||
},
|
||||
push(element: DialogElement, owner: Owner, onClose?: () => void) {
|
||||
setStore((s) => [...s, { element, onClose, owner }])
|
||||
},
|
||||
pop() {
|
||||
const current = store().at(-1)
|
||||
current?.onClose?.()
|
||||
setStore((stack) => stack.slice(0, -1))
|
||||
},
|
||||
replace(element: DialogElement, owner: Owner, onClose?: () => void) {
|
||||
for (const item of store()) {
|
||||
item.onClose?.()
|
||||
}
|
||||
setStore([{ element, onClose, owner }])
|
||||
},
|
||||
clear() {
|
||||
for (const item of store()) {
|
||||
item.onClose?.()
|
||||
}
|
||||
setStore([])
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function DialogProvider(props: ParentProps) {
|
||||
const ctx = init()
|
||||
const last = createMemo(() => ctx.stack.at(-1))
|
||||
return (
|
||||
<>
|
||||
<Context.Provider value={ctx}>
|
||||
{props.children}
|
||||
<Show when={dialog.stack.length > 0}>
|
||||
<div data-component="dialog-stack">
|
||||
<For each={dialog.stack}>
|
||||
{(item, index) => (
|
||||
<Show when={index() === dialog.stack.length - 1}>
|
||||
<div data-component="dialog-stack">
|
||||
<Show when={last()}>
|
||||
{(item) =>
|
||||
runWithOwner(item().owner, () => {
|
||||
return (
|
||||
<Kobalte
|
||||
modal
|
||||
defaultOpen
|
||||
onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
item.onClose?.()
|
||||
dialog.pop()
|
||||
item().onClose?.()
|
||||
ctx.pop()
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Kobalte.Portal>
|
||||
<Kobalte.Overlay data-component="dialog-overlay" />
|
||||
{typeof item.element === "function" ? item.element() : item.element}
|
||||
{item().element()}
|
||||
</Kobalte.Portal>
|
||||
</Kobalte>
|
||||
</Show>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</Show>
|
||||
</>
|
||||
)
|
||||
})
|
||||
}
|
||||
</Show>
|
||||
</div>
|
||||
</Context.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export function useDialog() {
|
||||
const ctx = useContext(Context)
|
||||
const owner = getOwner()
|
||||
if (!owner) {
|
||||
throw new Error("useDialog must be used within a DialogProvider")
|
||||
}
|
||||
if (!ctx) {
|
||||
throw new Error("useDialog must be used within a DialogProvider")
|
||||
}
|
||||
return {
|
||||
get stack() {
|
||||
return ctx.stack
|
||||
},
|
||||
replace(element: DialogElement, onClose?: () => void) {
|
||||
ctx.replace(element, owner, onClose)
|
||||
},
|
||||
push(element: DialogElement, onClose?: () => void) {
|
||||
ctx.push(element, owner, onClose)
|
||||
},
|
||||
pop() {
|
||||
ctx.pop()
|
||||
},
|
||||
clear() {
|
||||
ctx.clear()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue