diff --git a/packages/desktop/src/DesktopInterface.tsx b/packages/desktop/src/DesktopInterface.tsx index 1979308e4..31d52863d 100644 --- a/packages/desktop/src/DesktopInterface.tsx +++ b/packages/desktop/src/DesktopInterface.tsx @@ -2,19 +2,18 @@ import "@/index.css" import { Router, Route, Navigate } from "@solidjs/router" import { MetaProvider } from "@solidjs/meta" import { Font } from "@opencode-ai/ui/font" -import { Favicon } from "@opencode-ai/ui/favicon" import { MarkedProvider } from "@opencode-ai/ui/context/marked" import { DiffComponentProvider } from "@opencode-ai/ui/context/diff" import { Diff } from "@opencode-ai/ui/diff" -import { GlobalSyncProvider, useGlobalSync } from "./context/global-sync" +import { GlobalSyncProvider } from "./context/global-sync" import Layout from "@/pages/layout" +import Home from "@/pages/home" import DirectoryLayout from "@/pages/directory-layout" import Session from "@/pages/session" import { LayoutProvider } from "./context/layout" import { GlobalSDKProvider } from "./context/global-sdk" import { SessionProvider } from "./context/session" -import { base64Encode } from "@opencode-ai/util/encode" -import { createMemo, Show } from "solid-js" +import { Show } from "solid-js" const host = import.meta.env.VITE_OPENCODE_SERVER_HOST ?? "127.0.0.1" const port = import.meta.env.VITE_OPENCODE_SERVER_PORT ?? "4096" @@ -35,14 +34,7 @@ export function DesktopInterface() { - { - const globalSync = useGlobalSync() - const slug = createMemo(() => base64Encode(globalSync.data.defaultProject!.worktree)) - return - }} - /> + } /> { const [globalStore, setGlobalStore] = createStore<{ ready: boolean - defaultProject?: Project // TODO: remove this when we can select projects projects: Project[] children: Record }>({ @@ -165,11 +164,11 @@ export const { use: useGlobalSync, provider: GlobalSyncProvider } = createSimple sdk.client.project.list().then((x) => setGlobalStore( "projects", - x.data!.filter((x) => !x.worktree.includes("opencode-test")), + x + .data!.filter((x) => !x.worktree.includes("opencode-test") && x.vcs) + .sort((a, b) => b.time.created - a.time.created), ), ), - // TODO: remove this when we can select projects - sdk.client.project.current().then((x) => setGlobalStore("defaultProject", x.data)), ]).then(() => setGlobalStore("ready", true)) return { diff --git a/packages/desktop/src/context/layout.tsx b/packages/desktop/src/context/layout.tsx index ca736e84e..1b43cf511 100644 --- a/packages/desktop/src/context/layout.tsx +++ b/packages/desktop/src/context/layout.tsx @@ -2,17 +2,15 @@ import { createStore } from "solid-js/store" import { createMemo } from "solid-js" import { createSimpleContext } from "@opencode-ai/ui/context" import { makePersisted } from "@solid-primitives/storage" -import { useGlobalSync } from "./global-sync" export const { use: useLayout, provider: LayoutProvider } = createSimpleContext({ name: "Layout", init: () => { - const globalSync = useGlobalSync() const [store, setStore] = makePersisted( createStore({ - projects: [] as { directory: string; expanded: boolean }[], + projects: [] as { directory: string; expanded: boolean; lastSession?: string }[], sidebar: { - opened: true, + opened: false, width: 280, }, terminal: { @@ -24,17 +22,13 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( }, }), { - name: "____default-layout", + name: "default-layout.v4", }, ) return { projects: { - list: createMemo(() => - globalSync.data.defaultProject - ? [{ directory: globalSync.data.defaultProject!.worktree, expanded: true }, ...store.projects] - : store.projects, - ), + list: createMemo(() => store.projects), open(directory: string) { if (store.projects.find((x) => x.directory === directory)) return setStore("projects", (x) => [...x, { directory, expanded: true }]) @@ -48,6 +42,12 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( collapse(directory: string) { setStore("projects", (x) => x.map((x) => (x.directory === directory ? { ...x, expanded: false } : x))) }, + lastSession(directory: string) { + return store.projects.find((x) => x.directory === directory)?.lastSession + }, + setLastSession(directory: string, session: string | undefined) { + setStore("projects", (x) => x.map((x) => (x.directory === directory ? { ...x, lastSession: session } : x))) + }, }, sidebar: { opened: createMemo(() => store.sidebar.opened), diff --git a/packages/desktop/src/pages/home.tsx b/packages/desktop/src/pages/home.tsx index c35d5754e..469e2b7f7 100644 --- a/packages/desktop/src/pages/home.tsx +++ b/packages/desktop/src/pages/home.tsx @@ -1,21 +1,63 @@ import { useGlobalSync } from "@/context/global-sync" -import { base64Encode } from "@opencode-ai/util/encode" -import { For } from "solid-js" -import { A } from "@solidjs/router" +import { For, Match, Switch } from "solid-js" import { Button } from "@opencode-ai/ui/button" -import { getFilename } from "@opencode-ai/util/path" +import { Logo } from "@opencode-ai/ui/logo" +import { useLayout } from "@/context/layout" +import { useNavigate } from "@solidjs/router" +import { base64Encode } from "@opencode-ai/util/encode" +import { Icon } from "@opencode-ai/ui/icon" export default function Home() { + const navigate = useNavigate() const sync = useGlobalSync() + const layout = useLayout() + + function openProject(directory: string) { + layout.projects.open(directory) + navigate(`/${base64Encode(directory)}`) + } + return ( -
- - {(project) => ( - - )} - +
+ + + 0}> +
+
+
Recent projects
+ +
+
    + + {(project) => ( + + )} + +
+
+
+ +
+ +
+
No recent projects
+
Get started by opening a local project
+
+
+ +
+ +
) } diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index 166ee7beb..03eeedfb1 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -1,10 +1,11 @@ -import { createMemo, For, ParentProps, Show } from "solid-js" +import { createEffect, createMemo, For, Match, ParentProps, Show, Switch } from "solid-js" import { DateTime } from "luxon" import { A, useNavigate, useParams } from "@solidjs/router" import { useLayout } from "@/context/layout" import { useGlobalSync } from "@/context/global-sync" import { base64Decode, base64Encode } from "@opencode-ai/util/encode" import { Mark } from "@opencode-ai/ui/logo" +import { Avatar } from "@opencode-ai/ui/avatar" import { ResizeHandle } from "@opencode-ai/ui/resize-handle" import { Button } from "@opencode-ai/ui/button" import { Icon } from "@opencode-ai/ui/icon" @@ -14,6 +15,7 @@ import { Collapsible } from "@opencode-ai/ui/collapsible" import { DiffChanges } from "@opencode-ai/ui/diff-changes" import { getFilename } from "@opencode-ai/util/path" import { Select } from "@opencode-ai/ui/select" +import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu" import { Session } from "@opencode-ai/sdk/v2/client" export default function Layout(props: ParentProps) { @@ -25,15 +27,30 @@ export default function Layout(props: ParentProps) { const sessions = createMemo(() => globalSync.child(currentDirectory())[0].session ?? []) const currentSession = createMemo(() => sessions().find((s) => s.id === params.id)) + function navigateToProject(directory: string | undefined) { + if (!directory) return + navigate(`/${base64Encode(directory)}`) + } + function navigateToSession(session: Session | undefined) { if (!session) return navigate(`/${params.dir}/session/${session?.id}`) } + function closeProject(directory: string) { + layout.projects.close(directory) + navigate("/") + } + const handleOpenProject = async () => { // layout.projects.open(dir.) } + // createEffect(() => { + // if (!params.dir) return + // layout.projects.setLastSession(base64Decode(params.dir), params.id) + // }) + return (
@@ -50,61 +67,72 @@ export default function Layout(props: ParentProps) {
-
-
- x.title} - value={(x) => x.id} - onSelect={navigateToSession} - class="text-14-regular text-text-base max-w-md" - variant="ghost" - /> -
- -
-
- - Toggle terminal - Ctrl ` -
- } - > -