From 58b9b54600f12ba4ec1d80a2d1b7dee3879a0479 Mon Sep 17 00:00:00 2001 From: adamelmore <2363879+adamdottv@users.noreply.github.com> Date: Mon, 26 Jan 2026 22:58:29 -0600 Subject: [PATCH] feat(app): forward and back buttons --- packages/app/src/components/titlebar.tsx | 135 ++++++++++++++++++----- packages/app/src/context/platform.tsx | 6 + packages/app/src/entry.tsx | 6 + packages/app/src/i18n/en.ts | 1 + packages/desktop/src/index.tsx | 8 ++ packages/ui/src/components/icon.tsx | 1 + 6 files changed, 130 insertions(+), 27 deletions(-) diff --git a/packages/app/src/components/titlebar.tsx b/packages/app/src/components/titlebar.tsx index 159216a4f..1c8256069 100644 --- a/packages/app/src/components/titlebar.tsx +++ b/packages/app/src/components/titlebar.tsx @@ -1,8 +1,10 @@ -import { createEffect, createMemo, Show } from "solid-js" +import { createEffect, createMemo, Show, untrack } from "solid-js" +import { createStore } from "solid-js/store" +import { useLocation, useNavigate } from "@solidjs/router" import { IconButton } from "@opencode-ai/ui/icon-button" import { Icon } from "@opencode-ai/ui/icon" import { Button } from "@opencode-ai/ui/button" -import { TooltipKeybind } from "@opencode-ai/ui/tooltip" +import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip" import { useTheme } from "@opencode-ai/ui/theme" import { useLayout } from "@/context/layout" @@ -16,11 +18,68 @@ export function Titlebar() { const command = useCommand() const language = useLanguage() const theme = useTheme() + const navigate = useNavigate() + const location = useLocation() const mac = createMemo(() => platform.platform === "desktop" && platform.os === "macos") const windows = createMemo(() => platform.platform === "desktop" && platform.os === "windows") const web = createMemo(() => platform.platform === "web") + const [history, setHistory] = createStore({ + stack: [] as string[], + index: 0, + action: undefined as "back" | "forward" | undefined, + }) + + const path = () => `${location.pathname}${location.search}${location.hash}` + + createEffect(() => { + const current = path() + + untrack(() => { + if (!history.stack.length) { + const stack = current === "/" ? ["/"] : ["/", current] + setHistory({ stack, index: stack.length - 1 }) + return + } + + const active = history.stack[history.index] + if (current === active) { + if (history.action) setHistory("action", undefined) + return + } + + if (history.action) { + setHistory("action", undefined) + return + } + + const next = history.stack.slice(0, history.index + 1).concat(current) + setHistory({ stack: next, index: next.length - 1 }) + }) + }) + + const canBack = createMemo(() => history.index > 0) + const canForward = createMemo(() => history.index < history.stack.length - 1) + + const back = () => { + if (!canBack()) return + const index = history.index - 1 + const to = history.stack[index] + if (!to) return + setHistory({ index, action: "back" }) + navigate(to) + } + + const forward = () => { + if (!canForward()) return + const index = history.index + 1 + const to = history.stack[index] + if (!to) return + setHistory({ index, action: "forward" }) + navigate(to) + } + const getWin = () => { if (platform.platform !== "desktop") return @@ -106,34 +165,56 @@ export function Titlebar() { /> - - + + - - + + +
+ /** Navigate back in history */ + back(): void + + /** Navigate forward in history */ + forward(): void + /** Send a system notification (optional deep link) */ notify(title: string, description?: string, href?: string): Promise diff --git a/packages/app/src/entry.tsx b/packages/app/src/entry.tsx index 7fe03bb6a..aa52fa1e7 100644 --- a/packages/app/src/entry.tsx +++ b/packages/app/src/entry.tsx @@ -31,6 +31,12 @@ const platform: Platform = { openLink(url: string) { window.open(url, "_blank") }, + back() { + window.history.back() + }, + forward() { + window.history.forward() + }, restart: async () => { window.location.reload() }, diff --git a/packages/app/src/i18n/en.ts b/packages/app/src/i18n/en.ts index bca08275f..abbe497dc 100644 --- a/packages/app/src/i18n/en.ts +++ b/packages/app/src/i18n/en.ts @@ -167,6 +167,7 @@ export const dict = { "common.search.placeholder": "Search", "common.goBack": "Go back", + "common.goForward": "Go forward", "common.loading": "Loading", "common.loading.ellipsis": "...", "common.cancel": "Cancel", diff --git a/packages/desktop/src/index.tsx b/packages/desktop/src/index.tsx index fe9e3f92e..b19adfeda 100644 --- a/packages/desktop/src/index.tsx +++ b/packages/desktop/src/index.tsx @@ -80,6 +80,14 @@ const createPlatform = (password: Accessor): Platform => ({ void shellOpen(url).catch(() => undefined) }, + back() { + window.history.back() + }, + + forward() { + window.history.forward() + }, + storage: (() => { type StoreLike = { get(key: string): Promise diff --git a/packages/ui/src/components/icon.tsx b/packages/ui/src/components/icon.tsx index ddedddb36..544c6abdd 100644 --- a/packages/ui/src/components/icon.tsx +++ b/packages/ui/src/components/icon.tsx @@ -4,6 +4,7 @@ const icons = { "align-right": ``, "arrow-up": ``, "arrow-left": ``, + "arrow-right": ``, archive: ``, "bubble-5": ``, brain: ``,