|
|
@@ -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() {
|
|
|
/>
|
|
|
</div>
|
|
|
</Show>
|
|
|
- <TooltipKeybind
|
|
|
- class={web() ? "hidden xl:flex shrink-0 ml-14" : "hidden xl:flex shrink-0 ml-2"}
|
|
|
- placement="bottom"
|
|
|
- title={language.t("command.sidebar.toggle")}
|
|
|
- keybind={command.keybind("sidebar.toggle")}
|
|
|
- >
|
|
|
- <Button
|
|
|
- variant="ghost"
|
|
|
- class="group/sidebar-toggle size-6 p-0"
|
|
|
- onClick={layout.sidebar.toggle}
|
|
|
- aria-label={language.t("command.sidebar.toggle")}
|
|
|
- aria-expanded={layout.sidebar.opened()}
|
|
|
+ <div class="flex items-center gap-1 shrink-0">
|
|
|
+ <TooltipKeybind
|
|
|
+ class={web() ? "hidden xl:flex shrink-0 ml-14" : "hidden xl:flex shrink-0 ml-2"}
|
|
|
+ placement="bottom"
|
|
|
+ title={language.t("command.sidebar.toggle")}
|
|
|
+ keybind={command.keybind("sidebar.toggle")}
|
|
|
>
|
|
|
- <div class="relative flex items-center justify-center size-4 [&>*]:absolute [&>*]:inset-0">
|
|
|
- <Icon
|
|
|
- size="small"
|
|
|
- name={layout.sidebar.opened() ? "layout-left-full" : "layout-left"}
|
|
|
- class="group-hover/sidebar-toggle:hidden"
|
|
|
+ <Button
|
|
|
+ variant="ghost"
|
|
|
+ class="group/sidebar-toggle size-6 p-0"
|
|
|
+ onClick={layout.sidebar.toggle}
|
|
|
+ aria-label={language.t("command.sidebar.toggle")}
|
|
|
+ aria-expanded={layout.sidebar.opened()}
|
|
|
+ >
|
|
|
+ <div class="relative flex items-center justify-center size-4 [&>*]:absolute [&>*]:inset-0">
|
|
|
+ <Icon
|
|
|
+ size="small"
|
|
|
+ name={layout.sidebar.opened() ? "layout-left-full" : "layout-left"}
|
|
|
+ class="group-hover/sidebar-toggle:hidden"
|
|
|
+ />
|
|
|
+ <Icon size="small" name="layout-left-partial" class="hidden group-hover/sidebar-toggle:inline-block" />
|
|
|
+ <Icon
|
|
|
+ size="small"
|
|
|
+ name={layout.sidebar.opened() ? "layout-left" : "layout-left-full"}
|
|
|
+ class="hidden group-active/sidebar-toggle:inline-block"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </Button>
|
|
|
+ </TooltipKeybind>
|
|
|
+ <div class="hidden xl:flex items-center gap-1 shrink-0">
|
|
|
+ <Tooltip placement="bottom" value={language.t("common.goBack")}>
|
|
|
+ <IconButton
|
|
|
+ icon="arrow-left"
|
|
|
+ variant="ghost"
|
|
|
+ disabled={!canBack()}
|
|
|
+ onClick={back}
|
|
|
+ aria-label={language.t("common.goBack")}
|
|
|
/>
|
|
|
- <Icon size="small" name="layout-left-partial" class="hidden group-hover/sidebar-toggle:inline-block" />
|
|
|
- <Icon
|
|
|
- size="small"
|
|
|
- name={layout.sidebar.opened() ? "layout-left" : "layout-left-full"}
|
|
|
- class="hidden group-active/sidebar-toggle:inline-block"
|
|
|
+ </Tooltip>
|
|
|
+ <Tooltip placement="bottom" value={language.t("common.goForward")}>
|
|
|
+ <IconButton
|
|
|
+ icon="arrow-right"
|
|
|
+ variant="ghost"
|
|
|
+ disabled={!canForward()}
|
|
|
+ onClick={forward}
|
|
|
+ aria-label={language.t("common.goForward")}
|
|
|
/>
|
|
|
- </div>
|
|
|
- </Button>
|
|
|
- </TooltipKeybind>
|
|
|
+ </Tooltip>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
<div id="opencode-titlebar-left" class="flex items-center gap-3 min-w-0 px-2" data-tauri-drag-region />
|
|
|
<div class="flex-1 h-full" data-tauri-drag-region />
|
|
|
<div
|