Przeglądaj źródła

fix(app): titlebar cleanup (#17206)

David Hill 1 miesiąc temu
rodzic
commit
184732fc20
27 zmienionych plików z 378 dodań i 366 usunięć
  1. 0 31
      packages/app/src/components/prompt-input.tsx
  2. 9 5
      packages/app/src/components/server/server-row.tsx
  3. 19 264
      packages/app/src/components/session/session-header.tsx
  4. 9 3
      packages/app/src/components/status-popover.tsx
  5. 9 14
      packages/app/src/components/titlebar.tsx
  6. 196 6
      packages/app/src/pages/session/message-timeline.tsx
  7. 0 0
      packages/ui/src/assets/icons/app/android-studio.svg
  8. 0 0
      packages/ui/src/assets/icons/app/antigravity.svg
  9. 16 1
      packages/ui/src/assets/icons/app/cursor.svg
  10. 0 0
      packages/ui/src/assets/icons/app/file-explorer.svg
  11. BIN
      packages/ui/src/assets/icons/app/finder.png
  12. 13 1
      packages/ui/src/assets/icons/app/ghostty.svg
  13. 0 7
      packages/ui/src/assets/icons/app/iterm2.svg
  14. 14 1
      packages/ui/src/assets/icons/app/powershell.svg
  15. 17 1
      packages/ui/src/assets/icons/app/sublimetext.svg
  16. BIN
      packages/ui/src/assets/icons/app/terminal.png
  17. BIN
      packages/ui/src/assets/icons/app/textmate.png
  18. 0 0
      packages/ui/src/assets/icons/app/vscode.svg
  19. BIN
      packages/ui/src/assets/icons/app/warp.png
  20. BIN
      packages/ui/src/assets/icons/app/xcode.png
  21. 14 14
      packages/ui/src/assets/icons/app/zed-dark.svg
  22. 14 14
      packages/ui/src/assets/icons/app/zed.svg
  23. 12 0
      packages/ui/src/components/button.css
  24. 10 0
      packages/ui/src/components/dropdown-menu.css
  25. 19 3
      packages/ui/src/components/icon.tsx
  26. 2 1
      packages/ui/src/components/message-part.css
  27. 5 0
      packages/ui/src/styles/tailwind/utilities.css

+ 0 - 31
packages/app/src/components/prompt-input.tsx

@@ -26,7 +26,6 @@ import { ProviderIcon } from "@opencode-ai/ui/provider-icon"
 import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip"
 import { IconButton } from "@opencode-ai/ui/icon-button"
 import { Select } from "@opencode-ai/ui/select"
-import { RadioGroup } from "@opencode-ai/ui/radio-group"
 import { useDialog } from "@opencode-ai/ui/context/dialog"
 import { ModelSelectorPopover } from "@/components/dialog-select-model"
 import { DialogSelectModelUnpaid } from "@/components/dialog-select-model-unpaid"
@@ -1488,36 +1487,6 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
                 </TooltipKeybind>
               </div>
             </div>
-            <div class="shrink-0">
-              <RadioGroup
-                options={["shell", "normal"] as const}
-                current={store.mode}
-                value={(mode) => mode}
-                label={(mode) => (
-                  <TooltipKeybind
-                    placement="top"
-                    gutter={4}
-                    openDelay={2000}
-                    title={language.t(mode === "shell" ? "prompt.mode.shell" : "prompt.mode.normal")}
-                    keybind={command.keybind(mode === "shell" ? "prompt.mode.shell" : "prompt.mode.normal")}
-                    class="size-full flex items-center justify-center"
-                  >
-                    <Icon
-                      name={mode === "shell" ? "console" : "prompt"}
-                      class="size-[18px]"
-                      classList={{
-                        "text-icon-strong-base": store.mode === mode,
-                        "text-icon-weak": store.mode !== mode,
-                      }}
-                    />
-                  </TooltipKeybind>
-                )}
-                onSelect={(mode) => mode && setMode(mode)}
-                fill
-                pad="none"
-                class="w-[68px]"
-              />
-            </div>
           </div>
         </DockTray>
       </Show>

+ 9 - 5
packages/app/src/components/server/server-row.tsx

@@ -65,22 +65,26 @@ export function ServerRow(props: ServerRowProps) {
 
   return (
     <Tooltip
-      class="flex-1"
+      class="flex-1 min-w-0"
       value={tooltipValue()}
+      contentStyle={{ "max-width": "none", "white-space": "nowrap" }}
       placement="top-start"
       inactive={!truncated() && !props.conn.displayName}
     >
       <div class={props.class} classList={{ "opacity-50": props.dimmed }}>
-        <div class="flex flex-col items-start">
-          <div class="flex flex-row items-center gap-2">
-            <span ref={nameRef} class={props.nameClass ?? "truncate"}>
+        <div class="flex flex-col items-start min-w-0 w-full">
+          <div class="flex flex-row items-center gap-2 min-w-0 w-full">
+            <span ref={nameRef} class={`${props.nameClass ?? "truncate"} min-w-0`}>
               {name()}
             </span>
             <Show
               when={badge()}
               fallback={
                 <Show when={props.status?.version}>
-                  <span ref={versionRef} class={props.versionClass ?? "text-text-weak text-14-regular truncate"}>
+                  <span
+                    ref={versionRef}
+                    class={`${props.versionClass ?? "text-text-weak text-14-regular truncate"} min-w-0`}
+                  >
                     v{props.status?.version}
                   </span>
                 </Show>

+ 19 - 264
packages/app/src/components/session/session-header.tsx

@@ -4,9 +4,7 @@ import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu"
 import { Icon } from "@opencode-ai/ui/icon"
 import { IconButton } from "@opencode-ai/ui/icon-button"
 import { Keybind } from "@opencode-ai/ui/keybind"
-import { Popover } from "@opencode-ai/ui/popover"
 import { Spinner } from "@opencode-ai/ui/spinner"
-import { TextField } from "@opencode-ai/ui/text-field"
 import { showToast } from "@opencode-ai/ui/toast"
 import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip"
 import { getFilename } from "@opencode-ai/util/path"
@@ -14,12 +12,10 @@ import { createEffect, createMemo, For, onCleanup, Show } from "solid-js"
 import { createStore } from "solid-js/store"
 import { Portal } from "solid-js/web"
 import { useCommand } from "@/context/command"
-import { useGlobalSDK } from "@/context/global-sdk"
 import { useLanguage } from "@/context/language"
 import { useLayout } from "@/context/layout"
 import { usePlatform } from "@/context/platform"
 import { useServer } from "@/context/server"
-import { useSync } from "@/context/sync"
 import { useTerminal } from "@/context/terminal"
 import { focusTerminalById } from "@/pages/session/helpers"
 import { useSessionLayout } from "@/pages/session/session-layout"
@@ -112,12 +108,6 @@ const LINUX_APPS = [
   },
 ] as const
 
-type OpenOption = (typeof MAC_APPS)[number] | (typeof WINDOWS_APPS)[number] | (typeof LINUX_APPS)[number]
-type OpenIcon = OpenApp | "file-explorer"
-const OPEN_ICON_BASE = new Set<OpenIcon>(["finder", "vscode", "cursor", "zed"])
-
-const openIconSize = (id: OpenIcon) => (OPEN_ICON_BASE.has(id) ? "size-4" : "size-[19px]")
-
 const detectOS = (platform: ReturnType<typeof usePlatform>): OS => {
   if (platform.platform === "desktop" && platform.os) return platform.os
   if (typeof navigator !== "object") return "unknown"
@@ -136,98 +126,10 @@ const showRequestError = (language: ReturnType<typeof useLanguage>, err: unknown
   })
 }
 
-function useSessionShare(args: {
-  globalSDK: ReturnType<typeof useGlobalSDK>
-  currentSession: () =>
-    | {
-        share?: {
-          url?: string
-        }
-      }
-    | undefined
-  sessionID: () => string | undefined
-  projectDirectory: () => string
-  platform: ReturnType<typeof usePlatform>
-}) {
-  const [state, setState] = createStore({
-    share: false,
-    unshare: false,
-    copied: false,
-    timer: undefined as number | undefined,
-  })
-  const shareUrl = createMemo(() => args.currentSession()?.share?.url)
-
-  createEffect(() => {
-    const url = shareUrl()
-    if (url) return
-    if (state.timer) window.clearTimeout(state.timer)
-    setState({ copied: false, timer: undefined })
-  })
-
-  onCleanup(() => {
-    if (state.timer) window.clearTimeout(state.timer)
-  })
-
-  const shareSession = () => {
-    const sessionID = args.sessionID()
-    if (!sessionID || state.share) return
-    setState("share", true)
-    args.globalSDK.client.session
-      .share({ sessionID, directory: args.projectDirectory() })
-      .catch((error) => {
-        console.error("Failed to share session", error)
-      })
-      .finally(() => {
-        setState("share", false)
-      })
-  }
-
-  const unshareSession = () => {
-    const sessionID = args.sessionID()
-    if (!sessionID || state.unshare) return
-    setState("unshare", true)
-    args.globalSDK.client.session
-      .unshare({ sessionID, directory: args.projectDirectory() })
-      .catch((error) => {
-        console.error("Failed to unshare session", error)
-      })
-      .finally(() => {
-        setState("unshare", false)
-      })
-  }
-
-  const copyLink = (onError: (error: unknown) => void) => {
-    const url = shareUrl()
-    if (!url) return
-    navigator.clipboard
-      .writeText(url)
-      .then(() => {
-        if (state.timer) window.clearTimeout(state.timer)
-        setState("copied", true)
-        const timer = window.setTimeout(() => {
-          setState("copied", false)
-          setState("timer", undefined)
-        }, 3000)
-        setState("timer", timer)
-      })
-      .catch(onError)
-  }
-
-  const viewShare = () => {
-    const url = shareUrl()
-    if (!url) return
-    args.platform.openLink(url)
-  }
-
-  return { state, shareUrl, shareSession, unshareSession, copyLink, viewShare }
-}
-
 export function SessionHeader() {
-  const globalSDK = useGlobalSDK()
   const layout = useLayout()
   const command = useCommand()
   const server = useServer()
-  const sync = useSync()
   const platform = usePlatform()
   const language = useLanguage()
   const terminal = useTerminal()
@@ -245,10 +147,6 @@ export function SessionHeader() {
     return getFilename(projectDirectory())
   })
   const hotkey = createMemo(() => command.keybind("file.open"))
-
-  const currentSession = createMemo(() => (params.id ? sync.session.get(params.id) : undefined))
-  const shareEnabled = createMemo(() => sync.data.config.share !== "disabled")
-  const showShare = createMemo(() => shareEnabled() && !!params.id)
   const os = createMemo(() => detectOS(platform))
 
   const [exists, setExists] = createStore<Partial<Record<OpenApp, boolean>>>({
@@ -356,14 +254,6 @@ export function SessionHeader() {
       .catch((err: unknown) => showRequestError(language, err))
   }
 
-  const share = useSessionShare({
-    globalSDK,
-    currentSession,
-    sessionID: () => params.id,
-    projectDirectory,
-    platform,
-  })
-
   const centerMount = createMemo(() => document.getElementById("opencode-titlebar-center"))
   const rightMount = createMemo(() => document.getElementById("opencode-titlebar-right"))
 
@@ -391,7 +281,9 @@ export function SessionHeader() {
 
               <Show when={hotkey()}>
                 {(keybind) => (
-                  <Keybind class="shrink-0 !border-0 !bg-transparent !shadow-none px-0">{keybind()}</Keybind>
+                  <Keybind class="shrink-0 !border-0 !bg-transparent !shadow-none px-0 text-text-weaker">
+                    {keybind()}
+                  </Keybind>
                 )}
               </Show>
             </Button>
@@ -402,7 +294,6 @@ export function SessionHeader() {
         {(mount) => (
           <Portal mount={mount()}>
             <div class="flex items-center gap-2">
-              <StatusPopover />
               <Show when={projectDirectory()}>
                 <div class="hidden xl:flex items-center">
                   <Show
@@ -427,7 +318,7 @@ export function SessionHeader() {
                       <div class="flex h-[24px] box-border items-center rounded-md border border-border-weak-base bg-surface-panel overflow-hidden">
                         <Button
                           variant="ghost"
-                          class="rounded-none h-full py-0 pr-3 pl-0.5 gap-1.5 border-none shadow-none disabled:!cursor-default"
+                          class="rounded-none h-full py-0 pr-1.5 pl-px gap-1.5 border-none shadow-none disabled:!cursor-default"
                           classList={{
                             "bg-surface-raised-base-active": opening(),
                           }}
@@ -435,17 +326,13 @@ export function SessionHeader() {
                           disabled={opening()}
                           aria-label={language.t("session.header.open.ariaLabel", { app: current().label })}
                         >
-                          <div class="flex size-5 shrink-0 items-center justify-center">
-                            <Show
-                              when={opening()}
-                              fallback={<AppIcon id={current().icon} class={openIconSize(current().icon)} />}
-                            >
+                          <div class="flex size-5 shrink-0 items-center justify-center [&_[data-component=app-icon]]:size-5">
+                            <Show when={opening()} fallback={<AppIcon id={current().icon} />}>
                               <Spinner class="size-3.5 text-icon-base" />
                             </Show>
                           </div>
                           <span class="text-12-regular text-text-strong">{language.t("common.open")}</span>
                         </Button>
-                        <div class="self-stretch w-px bg-border-weak-base" />
                         <DropdownMenu
                           gutter={4}
                           placement="bottom-end"
@@ -457,17 +344,20 @@ export function SessionHeader() {
                             icon="chevron-down"
                             variant="ghost"
                             disabled={opening()}
-                            class="rounded-none h-full w-[24px] p-0 border-none shadow-none data-[expanded]:bg-surface-raised-base-active disabled:!cursor-default"
+                            class="rounded-none h-full w-[20px] p-0 border-none shadow-none data-[expanded]:bg-surface-raised-base-active disabled:!cursor-default"
                             classList={{
                               "bg-surface-raised-base-active": opening(),
                             }}
                             aria-label={language.t("session.header.open.menu")}
                           />
                           <DropdownMenu.Portal>
-                            <DropdownMenu.Content>
+                            <DropdownMenu.Content class="[&_[data-slot=dropdown-menu-item]]:pl-1 [&_[data-slot=dropdown-menu-radio-item]]:pl-1 [&_[data-slot=dropdown-menu-radio-item]+[data-slot=dropdown-menu-radio-item]]:mt-1">
                               <DropdownMenu.Group>
-                                <DropdownMenu.GroupLabel>{language.t("session.header.openIn")}</DropdownMenu.GroupLabel>
+                                <DropdownMenu.GroupLabel class="!px-1 !py-1">
+                                  {language.t("session.header.openIn")}
+                                </DropdownMenu.GroupLabel>
                                 <DropdownMenu.RadioGroup
+                                  class="mt-1"
                                   value={current().id}
                                   onChange={(value) => {
                                     if (!OPEN_APPS.includes(value as OpenApp)) return
@@ -484,8 +374,8 @@ export function SessionHeader() {
                                           openDir(o.id)
                                         }}
                                       >
-                                        <div class="flex size-5 shrink-0 items-center justify-center">
-                                          <AppIcon id={o.icon} class={openIconSize(o.icon)} />
+                                        <div class="flex size-5 shrink-0 items-center justify-center [&_[data-component=app-icon]]:size-5">
+                                          <AppIcon id={o.icon} />
                                         </div>
                                         <DropdownMenu.ItemLabel>{o.label}</DropdownMenu.ItemLabel>
                                         <DropdownMenu.ItemIndicator>
@@ -518,113 +408,10 @@ export function SessionHeader() {
                   </Show>
                 </div>
               </Show>
-              <Show when={showShare()}>
-                <div class="flex items-center">
-                  <Popover
-                    title={language.t("session.share.popover.title")}
-                    description={
-                      share.shareUrl()
-                        ? language.t("session.share.popover.description.shared")
-                        : language.t("session.share.popover.description.unshared")
-                    }
-                    gutter={4}
-                    placement="bottom-end"
-                    shift={-64}
-                    class="rounded-xl [&_[data-slot=popover-close-button]]:hidden"
-                    triggerAs={Button}
-                    triggerProps={{
-                      variant: "ghost",
-                      class:
-                        "rounded-md h-[24px] px-3 border border-border-weak-base bg-surface-panel shadow-none data-[expanded]:bg-surface-base-active",
-                      classList: {
-                        "rounded-r-none": share.shareUrl() !== undefined,
-                        "border-r-0": share.shareUrl() !== undefined,
-                      },
-                      style: { scale: 1 },
-                    }}
-                    trigger={<span class="text-12-regular">{language.t("session.share.action.share")}</span>}
-                  >
-                    <div class="flex flex-col gap-2">
-                      <Show
-                        when={share.shareUrl()}
-                        fallback={
-                          <div class="flex">
-                            <Button
-                              size="large"
-                              variant="primary"
-                              class="w-1/2"
-                              onClick={share.shareSession}
-                              disabled={share.state.share}
-                            >
-                              {share.state.share
-                                ? language.t("session.share.action.publishing")
-                                : language.t("session.share.action.publish")}
-                            </Button>
-                          </div>
-                        }
-                      >
-                        <div class="flex flex-col gap-2">
-                          <TextField
-                            value={share.shareUrl() ?? ""}
-                            readOnly
-                            copyable
-                            copyKind="link"
-                            tabIndex={-1}
-                            class="w-full"
-                          />
-                          <div class="grid grid-cols-2 gap-2">
-                            <Button
-                              size="large"
-                              variant="secondary"
-                              class="w-full shadow-none border border-border-weak-base"
-                              onClick={share.unshareSession}
-                              disabled={share.state.unshare}
-                            >
-                              {share.state.unshare
-                                ? language.t("session.share.action.unpublishing")
-                                : language.t("session.share.action.unpublish")}
-                            </Button>
-                            <Button
-                              size="large"
-                              variant="primary"
-                              class="w-full"
-                              onClick={share.viewShare}
-                              disabled={share.state.unshare}
-                            >
-                              {language.t("session.share.action.view")}
-                            </Button>
-                          </div>
-                        </div>
-                      </Show>
-                    </div>
-                  </Popover>
-                  <Show when={share.shareUrl()} fallback={<div aria-hidden="true" />}>
-                    <Tooltip
-                      value={
-                        share.state.copied
-                          ? language.t("session.share.copy.copied")
-                          : language.t("session.share.copy.copyLink")
-                      }
-                      placement="top"
-                      gutter={8}
-                    >
-                      <IconButton
-                        icon={share.state.copied ? "check" : "link"}
-                        variant="ghost"
-                        class="rounded-l-none h-[24px] border border-border-weak-base bg-surface-panel shadow-none"
-                        onClick={() => share.copyLink((error) => showRequestError(language, error))}
-                        disabled={share.state.unshare}
-                        aria-label={
-                          share.state.copied
-                            ? language.t("session.share.copy.copied")
-                            : language.t("session.share.copy.copyLink")
-                        }
-                      />
-                    </Tooltip>
-                  </Show>
-                </div>
-              </Show>
               <div class="flex items-center gap-1">
+                <Tooltip placement="bottom" value={language.t("status.popover.trigger")}>
+                  <StatusPopover />
+                </Tooltip>
                 <TooltipKeybind
                   title={language.t("command.terminal.toggle")}
                   keybind={command.keybind("terminal.toggle")}
@@ -637,23 +424,7 @@ export function SessionHeader() {
                     aria-expanded={view().terminal.opened()}
                     aria-controls="terminal-panel"
                   >
-                    <div class="relative flex items-center justify-center size-4 [&>*]:absolute [&>*]:inset-0">
-                      <Icon
-                        size="small"
-                        name={view().terminal.opened() ? "layout-bottom-partial" : "layout-bottom"}
-                        class="group-hover/terminal-toggle:hidden"
-                      />
-                      <Icon
-                        size="small"
-                        name="layout-bottom-partial"
-                        class="hidden group-hover/terminal-toggle:inline-block"
-                      />
-                      <Icon
-                        size="small"
-                        name={view().terminal.opened() ? "layout-bottom" : "layout-bottom-partial"}
-                        class="hidden group-active/terminal-toggle:inline-block"
-                      />
-                    </div>
+                    <Icon size="small" name={view().terminal.opened() ? "terminal-active" : "terminal"} />
                   </Button>
                 </TooltipKeybind>
 
@@ -670,23 +441,7 @@ export function SessionHeader() {
                       aria-expanded={view().reviewPanel.opened()}
                       aria-controls="review-panel"
                     >
-                      <div class="relative flex items-center justify-center size-4 [&>*]:absolute [&>*]:inset-0">
-                        <Icon
-                          size="small"
-                          name={view().reviewPanel.opened() ? "layout-right-partial" : "layout-right"}
-                          class="group-hover/review-toggle:hidden"
-                        />
-                        <Icon
-                          size="small"
-                          name="layout-right-partial"
-                          class="hidden group-hover/review-toggle:inline-block"
-                        />
-                        <Icon
-                          size="small"
-                          name={view().reviewPanel.opened() ? "layout-right" : "layout-right-partial"}
-                          class="hidden group-active/review-toggle:inline-block"
-                        />
-                      </div>
+                      <Icon size="small" name={view().reviewPanel.opened() ? "review-active" : "review"} />
                     </Button>
                   </TooltipKeybind>
 

+ 9 - 3
packages/app/src/components/status-popover.tsx

@@ -169,6 +169,7 @@ export function StatusPopover() {
   const language = useLanguage()
   const navigate = useNavigate()
 
+  const [shown, setShown] = createSignal(false)
   const servers = createMemo(() => {
     const current = server.current
     const list = server.list
@@ -199,18 +200,23 @@ export function StatusPopover() {
 
   return (
     <Popover
+      open={shown()}
+      onOpenChange={setShown}
       triggerAs={Button}
       triggerProps={{
         variant: "ghost",
-        class: "titlebar-icon w-6 h-6 p-0 box-border",
+        class: "titlebar-icon w-8 h-6 p-0 box-border",
         "aria-label": language.t("status.popover.trigger"),
         style: { scale: 1 },
       }}
       trigger={
-        <div class="flex size-4 items-center justify-center">
+        <div class="relative size-4">
+          <div class="badge-mask-tight size-4 flex items-center justify-center">
+            <Icon name={shown() ? "status-active" : "status"} size="small" />
+          </div>
           <div
             classList={{
-              "size-1.5 rounded-full": true,
+              "absolute -top-px -right-px size-1.5 rounded-full": true,
               "bg-icon-success-base": overallHealthy(),
               "bg-icon-critical-base": !overallHealthy() && server.healthy() !== undefined,
               "bg-border-weak-base": server.healthy() === undefined,

+ 9 - 14
packages/app/src/components/titlebar.tsx

@@ -58,6 +58,12 @@ export function Titlebar() {
   })
 
   const path = () => `${location.pathname}${location.search}${location.hash}`
+  const creating = createMemo(() => {
+    if (!params.dir) return false
+    if (params.id) return false
+    const parts = location.pathname.replace(/\/+$/, "").split("/")
+    return parts.at(-1) === "session"
+  })
 
   createEffect(() => {
     const current = path()
@@ -206,19 +212,7 @@ export function Titlebar() {
               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-partial" : "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-partial"}
-                  class="hidden group-active/sidebar-toggle:inline-block"
-                />
-              </div>
+              <Icon size="small" name={layout.sidebar.opened() ? "sidebar-active" : "sidebar"} />
             </Button>
           </TooltipKeybind>
           <div class="hidden xl:flex items-center shrink-0">
@@ -231,13 +225,14 @@ export function Titlebar() {
               >
                 <Button
                   variant="ghost"
-                  icon="new-session"
+                  icon={creating() ? "new-session-active" : "new-session"}
                   class="titlebar-icon w-8 h-6 p-0 box-border"
                   onClick={() => {
                     if (!params.dir) return
                     navigate(`/${params.dir}/session`)
                   }}
                   aria-label={language.t("command.session.new")}
+                  aria-current={creating() ? "page" : undefined}
                 />
               </TooltipKeybind>
             </Show>

+ 196 - 6
packages/app/src/pages/session/message-timeline.tsx

@@ -11,15 +11,19 @@ import { InlineInput } from "@opencode-ai/ui/inline-input"
 import { Spinner } from "@opencode-ai/ui/spinner"
 import { SessionTurn } from "@opencode-ai/ui/session-turn"
 import { ScrollView } from "@opencode-ai/ui/scroll-view"
+import { TextField } from "@opencode-ai/ui/text-field"
 import type { AssistantMessage, Message as MessageType, Part, TextPart, UserMessage } from "@opencode-ai/sdk/v2"
 import { showToast } from "@opencode-ai/ui/toast"
 import { Binary } from "@opencode-ai/util/binary"
 import { getFilename } from "@opencode-ai/util/path"
+import { Popover as KobaltePopover } from "@kobalte/core/popover"
 import { shouldMarkBoundaryGesture, normalizeWheelDelta } from "@/pages/session/message-gesture"
 import { SessionContextUsage } from "@/components/session-context-usage"
 import { useDialog } from "@opencode-ai/ui/context/dialog"
 import { useLanguage } from "@/context/language"
 import { useSessionKey } from "@/pages/session/session-layout"
+import { useGlobalSDK } from "@/context/global-sdk"
+import { usePlatform } from "@/context/platform"
 import { useSettings } from "@/context/settings"
 import { useSDK } from "@/context/sdk"
 import { useSync } from "@/context/sync"
@@ -215,12 +219,14 @@ export function MessageTimeline(props: {
   let touchGesture: number | undefined
 
   const navigate = useNavigate()
+  const globalSDK = useGlobalSDK()
   const sdk = useSDK()
   const sync = useSync()
   const settings = useSettings()
   const dialog = useDialog()
   const language = useLanguage()
   const { params, sessionKey } = useSessionKey()
+  const platform = usePlatform()
 
   const rendered = createMemo(() => props.renderedUserMessages.map((message) => message.id))
   const sessionID = createMemo(() => params.id)
@@ -298,6 +304,8 @@ export function MessageTimeline(props: {
     return sync.session.get(id)
   })
   const titleValue = createMemo(() => info()?.title)
+  const shareUrl = createMemo(() => info()?.share?.url)
+  const shareEnabled = createMemo(() => sync.data.config.share !== "disabled")
   const parentID = createMemo(() => info()?.parentID)
   const showHeader = createMemo(() => !!(titleValue() || parentID()))
   const stageCfg = { init: 1, batch: 3 }
@@ -314,9 +322,55 @@ export function MessageTimeline(props: {
     saving: false,
     menuOpen: false,
     pendingRename: false,
+    pendingShare: false,
   })
   let titleRef: HTMLInputElement | undefined
 
+  const [share, setShare] = createStore({
+    open: false,
+    dismiss: null as "escape" | "outside" | null,
+  })
+
+  let more: HTMLButtonElement | undefined
+
+  const [req, setReq] = createStore({ share: false, unshare: false })
+
+  const shareSession = () => {
+    const id = sessionID()
+    if (!id || req.share) return
+    if (!shareEnabled()) return
+    setReq("share", true)
+    globalSDK.client.session
+      .share({ sessionID: id, directory: sdk.directory })
+      .catch((err: unknown) => {
+        console.error("Failed to share session", err)
+      })
+      .finally(() => {
+        setReq("share", false)
+      })
+  }
+
+  const unshareSession = () => {
+    const id = sessionID()
+    if (!id || req.unshare) return
+    if (!shareEnabled()) return
+    setReq("unshare", true)
+    globalSDK.client.session
+      .unshare({ sessionID: id, directory: sdk.directory })
+      .catch((err: unknown) => {
+        console.error("Failed to unshare session", err)
+      })
+      .finally(() => {
+        setReq("unshare", false)
+      })
+  }
+
+  const viewShare = () => {
+    const url = shareUrl()
+    if (!url) return
+    platform.openLink(url)
+  }
+
   const errorMessage = (err: unknown) => {
     if (err && typeof err === "object" && "data" in err) {
       const data = (err as { data?: { message?: string } }).data
@@ -329,7 +383,15 @@ export function MessageTimeline(props: {
   createEffect(
     on(
       sessionKey,
-      () => setTitle({ draft: "", editing: false, saving: false, menuOpen: false, pendingRename: false }),
+      () =>
+        setTitle({
+          draft: "",
+          editing: false,
+          saving: false,
+          menuOpen: false,
+          pendingRename: false,
+          pendingShare: false,
+        }),
       { defer: true },
     ),
   )
@@ -678,23 +740,42 @@ export function MessageTimeline(props: {
                           gutter={4}
                           placement="bottom-end"
                           open={title.menuOpen}
-                          onOpenChange={(open) => setTitle("menuOpen", open)}
+                          onOpenChange={(open) => {
+                            setTitle("menuOpen", open)
+                            if (open) return
+                          }}
                         >
                           <DropdownMenu.Trigger
                             as={IconButton}
                             icon="dot-grid"
                             variant="ghost"
                             class="size-6 rounded-md data-[expanded]:bg-surface-base-active"
+                            classList={{
+                              "bg-surface-base-active": share.open || title.pendingShare,
+                            }}
                             aria-label={language.t("common.moreOptions")}
+                            aria-expanded={title.menuOpen || share.open || title.pendingShare}
+                            ref={(el: HTMLButtonElement) => {
+                              more = el
+                            }}
                           />
                           <DropdownMenu.Portal>
                             <DropdownMenu.Content
                               style={{ "min-width": "104px" }}
                               onCloseAutoFocus={(event) => {
-                                if (!title.pendingRename) return
-                                event.preventDefault()
-                                setTitle("pendingRename", false)
-                                openTitleEditor()
+                                if (title.pendingRename) {
+                                  event.preventDefault()
+                                  setTitle("pendingRename", false)
+                                  openTitleEditor()
+                                  return
+                                }
+                                if (title.pendingShare) {
+                                  event.preventDefault()
+                                  requestAnimationFrame(() => {
+                                    setShare({ open: true, dismiss: null })
+                                    setTitle("pendingShare", false)
+                                  })
+                                }
                               }}
                             >
                               <DropdownMenu.Item
@@ -705,6 +786,17 @@ export function MessageTimeline(props: {
                               >
                                 <DropdownMenu.ItemLabel>{language.t("common.rename")}</DropdownMenu.ItemLabel>
                               </DropdownMenu.Item>
+                              <Show when={shareEnabled()}>
+                                <DropdownMenu.Item
+                                  onSelect={() => {
+                                    setTitle({ pendingShare: true, menuOpen: false })
+                                  }}
+                                >
+                                  <DropdownMenu.ItemLabel>
+                                    {language.t("session.share.action.share")}
+                                  </DropdownMenu.ItemLabel>
+                                </DropdownMenu.Item>
+                              </Show>
                               <DropdownMenu.Item onSelect={() => void archiveSession(id())}>
                                 <DropdownMenu.ItemLabel>{language.t("common.archive")}</DropdownMenu.ItemLabel>
                               </DropdownMenu.Item>
@@ -717,6 +809,104 @@ export function MessageTimeline(props: {
                             </DropdownMenu.Content>
                           </DropdownMenu.Portal>
                         </DropdownMenu>
+
+                        <KobaltePopover
+                          open={share.open}
+                          anchorRef={() => more}
+                          placement="bottom-end"
+                          gutter={4}
+                          modal={false}
+                          onOpenChange={(open) => {
+                            if (open) setShare("dismiss", null)
+                            setShare("open", open)
+                          }}
+                        >
+                          <KobaltePopover.Portal>
+                            <KobaltePopover.Content
+                              data-component="popover-content"
+                              style={{ "min-width": "320px" }}
+                              onEscapeKeyDown={(event) => {
+                                setShare({ dismiss: "escape", open: false })
+                                event.preventDefault()
+                                event.stopPropagation()
+                              }}
+                              onPointerDownOutside={() => {
+                                setShare({ dismiss: "outside", open: false })
+                              }}
+                              onFocusOutside={() => {
+                                setShare({ dismiss: "outside", open: false })
+                              }}
+                              onCloseAutoFocus={(event) => {
+                                if (share.dismiss === "outside") event.preventDefault()
+                                setShare("dismiss", null)
+                              }}
+                            >
+                              <div class="flex flex-col p-3">
+                                <div class="flex flex-col gap-1">
+                                  <div class="text-13-medium text-text-strong">
+                                    {language.t("session.share.popover.title")}
+                                  </div>
+                                  <div class="text-12-regular text-text-weak">
+                                    {shareUrl()
+                                      ? language.t("session.share.popover.description.shared")
+                                      : language.t("session.share.popover.description.unshared")}
+                                  </div>
+                                </div>
+                                <div class="mt-3 flex flex-col gap-2">
+                                  <Show
+                                    when={shareUrl()}
+                                    fallback={
+                                      <Button
+                                        size="large"
+                                        variant="primary"
+                                        class="w-full"
+                                        onClick={shareSession}
+                                        disabled={req.share}
+                                      >
+                                        {req.share
+                                          ? language.t("session.share.action.publishing")
+                                          : language.t("session.share.action.publish")}
+                                      </Button>
+                                    }
+                                  >
+                                    <div class="flex flex-col gap-2">
+                                      <TextField
+                                        value={shareUrl() ?? ""}
+                                        readOnly
+                                        copyable
+                                        copyKind="link"
+                                        tabIndex={-1}
+                                        class="w-full"
+                                      />
+                                      <div class="grid grid-cols-2 gap-2">
+                                        <Button
+                                          size="large"
+                                          variant="secondary"
+                                          class="w-full shadow-none border border-border-weak-base"
+                                          onClick={unshareSession}
+                                          disabled={req.unshare}
+                                        >
+                                          {req.unshare
+                                            ? language.t("session.share.action.unpublishing")
+                                            : language.t("session.share.action.unpublish")}
+                                        </Button>
+                                        <Button
+                                          size="large"
+                                          variant="primary"
+                                          class="w-full"
+                                          onClick={viewShare}
+                                          disabled={req.unshare}
+                                        >
+                                          {language.t("session.share.action.view")}
+                                        </Button>
+                                      </div>
+                                    </div>
+                                  </Show>
+                                </div>
+                              </div>
+                            </KobaltePopover.Content>
+                          </KobaltePopover.Portal>
+                        </KobaltePopover>
                       </div>
                     )}
                   </Show>

Plik diff jest za duży
+ 0 - 0
packages/ui/src/assets/icons/app/android-studio.svg


Plik diff jest za duży
+ 0 - 0
packages/ui/src/assets/icons/app/antigravity.svg


+ 16 - 1
packages/ui/src/assets/icons/app/cursor.svg

@@ -1 +1,16 @@
-<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><g clip-path="url(#prefix__clip0_5_17)"><rect width="512" height="512" rx="122" fill="#000"/><g clip-path="url(#prefix__clip1_5_17)"><mask id="prefix__a" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="85" y="89" width="343" height="334"><path d="M85 89h343v334H85V89z" fill="#fff"/></mask><g mask="url(#prefix__a)"><path d="M255.428 423l148.991-83.5L255.428 256l-148.99 83.5 148.99 83.5z" fill="url(#prefix__paint0_linear_5_17)"/><path d="M404.419 339.5v-167L255.428 89v167l148.991 83.5z" fill="url(#prefix__paint1_linear_5_17)"/><path d="M255.428 89l-148.99 83.5v167l148.99-83.5V89z" fill="url(#prefix__paint2_linear_5_17)"/><path d="M404.419 172.5L255.428 423V256l148.991-83.5z" fill="#E4E4E4"/><path d="M404.419 172.5L255.428 256l-148.99-83.5h297.981z" fill="#fff"/></g></g></g><defs><linearGradient id="prefix__paint0_linear_5_17" x1="255.428" y1="256" x2="255.428" y2="423" gradientUnits="userSpaceOnUse"><stop offset=".16" stop-color="#fff" stop-opacity=".39"/><stop offset=".658" stop-color="#fff" stop-opacity=".8"/></linearGradient><linearGradient id="prefix__paint1_linear_5_17" x1="404.419" y1="173.015" x2="257.482" y2="261.497" gradientUnits="userSpaceOnUse"><stop offset=".182" stop-color="#fff" stop-opacity=".31"/><stop offset=".715" stop-color="#fff" stop-opacity="0"/></linearGradient><linearGradient id="prefix__paint2_linear_5_17" x1="255.428" y1="89" x2="112.292" y2="342.802" gradientUnits="userSpaceOnUse"><stop stop-color="#fff" stop-opacity=".6"/><stop offset=".667" stop-color="#fff" stop-opacity=".22"/></linearGradient><clipPath id="prefix__clip0_5_17"><path fill="#fff" d="M0 0h512v512H0z"/></clipPath><clipPath id="prefix__clip1_5_17"><path fill="#fff" transform="translate(85 89)" d="M0 0h343v334H0z"/></clipPath></defs></svg>
+<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_5436_78947)">
+<mask id="mask0_5436_78947" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="4" y="4" width="32" height="32">
+<path d="M4 4H36V36H4V4Z" fill="white"/>
+</mask>
+<g mask="url(#mask0_5436_78947)">
+<path d="M28.375 4H11.625C7.41383 4 4 7.41383 4 11.625V28.375C4 32.5862 7.41383 36 11.625 36H28.375C32.5862 36 36 32.5862 36 28.375V11.625C36 7.41383 32.5862 4 28.375 4Z" fill="black"/>
+</g>
+<path d="M29.6214 14.2072L20.9502 9.12249C20.6718 8.95917 20.3282 8.95917 20.0498 9.12249L11.3786 14.2072C11.1445 14.3445 11 14.5984 11 14.8733V25.1267C11 25.4012 11.1445 25.6555 11.3786 25.7928L20.0498 30.8775C20.3282 31.0408 20.6718 31.0408 20.9502 30.8775L29.6214 25.7928C29.8555 25.6555 30 25.4016 30 25.1267V14.8733C30 14.5988 29.8555 14.3445 29.6214 14.2072ZM29.0767 15.2843L20.706 30.0101C20.6494 30.1093 20.5 30.0688 20.5 29.9538V20.3115C20.5 20.1189 20.3986 19.9407 20.2342 19.8439L12.0124 15.0226C11.9147 14.9651 11.9546 14.8134 12.0678 14.8134H28.8093C29.047 14.8134 29.1956 15.0751 29.0767 15.2843Z" fill="white"/>
+</g>
+<defs>
+<clipPath id="clip0_5436_78947">
+<rect width="32" height="32" fill="white" transform="translate(4 4)"/>
+</clipPath>
+</defs>
+</svg>

Plik diff jest za duży
+ 0 - 0
packages/ui/src/assets/icons/app/file-explorer.svg


BIN
packages/ui/src/assets/icons/app/finder.png


+ 13 - 1
packages/ui/src/assets/icons/app/ghostty.svg

@@ -1 +1,13 @@
-<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 27 32"><path fill="#3551F3" d="M20.395 32a6.35 6.35 0 0 1-3.516-1.067A6.355 6.355 0 0 1 13.362 32c-1.249 0-2.48-.375-3.516-1.067A6.265 6.265 0 0 1 6.372 32h-.038a6.255 6.255 0 0 1-4.5-1.906 6.377 6.377 0 0 1-1.836-4.482v-12.25C0 5.995 5.994 0 13.362 0c7.369 0 13.363 5.994 13.363 13.363v12.253c0 3.393-2.626 6.192-5.978 6.375-.117.007-.234.009-.352.009Z"/><path fill="#000" d="M20.395 30.593a4.932 4.932 0 0 1-3.08-1.083.656.656 0 0 0-.42-.145.784.784 0 0 0-.487.176 4.939 4.939 0 0 1-3.046 1.055 4.939 4.939 0 0 1-3.045-1.055.751.751 0 0 0-.942 0 4.883 4.883 0 0 1-3.01 1.055h-.033a4.852 4.852 0 0 1-3.49-1.482 4.982 4.982 0 0 1-1.436-3.498V13.367c0-6.597 5.364-11.96 11.957-11.96 6.592 0 11.956 5.363 11.956 11.956v12.253c0 2.645-2.042 4.827-4.65 4.97a5.342 5.342 0 0 1-.274.007Z"/><path fill="#fff" d="M23.912 13.363v12.253c0 1.876-1.447 3.463-3.32 3.566a3.503 3.503 0 0 1-2.398-.769c-.778-.626-1.873-.598-2.658.021a3.5 3.5 0 0 1-2.176.753 3.494 3.494 0 0 1-2.173-.753 2.153 2.153 0 0 0-2.684 0 3.498 3.498 0 0 1-2.15.753c-1.948.014-3.54-1.627-3.54-3.575v-12.25c0-5.825 4.724-10.549 10.55-10.549 5.825 0 10.549 4.724 10.549 10.55Z"/><path fill="#000" d="m11.28 12.437-3.93-2.27a1.072 1.072 0 0 0-1.463.392 1.072 1.072 0 0 0 .391 1.463l2.326 1.343-2.326 1.343a1.072 1.072 0 0 0 1.071 1.855l3.932-2.27a1.071 1.071 0 0 0 0-1.854v-.002ZM20.182 12.291h-5.164a1.071 1.071 0 1 0 0 2.143h5.164a1.071 1.071 0 1 0 0-2.143Z"/></svg>
+<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_5437_79067)">
+<path d="M27.395 36C26.1435 35.9986 24.9203 35.6274 23.879 34.933C22.8374 35.6273 21.6139 35.9985 20.362 36C19.113 36 17.882 35.625 16.846 34.933C15.8189 35.6241 14.61 35.9954 13.372 36H13.334C12.4944 36.0006 11.6633 35.8321 10.8902 35.5047C10.1171 35.1772 9.41781 34.6975 8.83405 34.094C7.65642 32.8996 6.99679 31.2893 6.99805 29.612V17.362C7.00005 9.995 12.994 4 20.362 4C27.731 4 33.725 9.994 33.725 17.363V29.616C33.725 33.009 31.099 35.808 27.747 35.991C27.63 35.998 27.513 36 27.395 36Z" fill="#3551F3"/>
+<path d="M27.395 34.5932C26.2752 34.5924 25.1889 34.2104 24.315 33.5102C24.1961 33.4145 24.0476 33.3632 23.895 33.3652C23.7174 33.367 23.5457 33.4291 23.408 33.5412C22.5392 34.2237 21.4668 34.5951 20.362 34.5962C19.2576 34.5949 18.1855 34.2234 17.317 33.5412C17.1835 33.4338 17.0174 33.3752 16.846 33.3752C16.6747 33.3752 16.5085 33.4338 16.375 33.5412C15.518 34.2199 14.4581 34.5914 13.365 34.5962H13.332C12.6806 34.5961 12.0359 34.4649 11.4362 34.2102C10.8366 33.9556 10.2945 33.5829 9.84201 33.1142C8.92225 32.1822 8.40639 30.9256 8.40601 29.6162V17.3672C8.40601 10.7702 13.77 5.40723 20.363 5.40723C26.955 5.40723 32.319 10.7702 32.319 17.3632V29.6162C32.319 32.2612 30.277 34.4432 27.669 34.5862C27.5777 34.5909 27.4864 34.5932 27.395 34.5932Z" fill="black"/>
+<path d="M30.912 17.3635V29.6165C30.912 31.4925 29.465 33.0795 27.592 33.1825C26.725 33.2323 25.8704 32.9582 25.194 32.4135C24.416 31.7875 23.321 31.8155 22.536 32.4345C21.9163 32.9237 21.1495 33.1891 20.36 33.1875C19.5714 33.1889 18.8056 32.9235 18.187 32.4345C17.8057 32.1306 17.3326 31.9651 16.845 31.9651C16.3574 31.9651 15.8843 32.1306 15.503 32.4345C14.8904 32.9183 14.1336 33.1834 13.353 33.1875C11.405 33.2015 9.81299 31.5605 9.81299 29.6125V17.3625C9.81299 11.5375 14.537 6.81348 20.363 6.81348C26.188 6.81348 30.912 11.5375 30.912 17.3635Z" fill="white"/>
+<path d="M18.28 16.4366L14.35 14.1666C14.104 14.0248 13.8117 13.9865 13.5374 14.06C13.2632 14.1335 13.0292 14.3128 12.887 14.5586C12.7452 14.8045 12.7067 15.0966 12.78 15.3709C12.8533 15.6452 13.0324 15.8792 13.278 16.0216L15.604 17.3646L13.278 18.7076C13.045 18.8559 12.8783 19.0886 12.8126 19.3569C12.7469 19.6252 12.7873 19.9085 12.9255 20.1478C13.0636 20.387 13.2887 20.5637 13.554 20.641C13.8192 20.7183 14.104 20.6902 14.349 20.5626L18.281 18.2926C18.4436 18.1985 18.5786 18.0633 18.6724 17.9006C18.7662 17.7379 18.8156 17.5534 18.8156 17.3656C18.8156 17.1777 18.7662 16.9932 18.6724 16.8305C18.5786 16.6678 18.4436 16.5326 18.281 16.4386V16.4366H18.28ZM27.182 16.2906H22.018C21.7338 16.2906 21.4613 16.4034 21.2604 16.6044C21.0594 16.8053 20.9465 17.0779 20.9465 17.3621C20.9465 17.6462 21.0594 17.9188 21.2604 18.1197C21.4613 18.3207 21.7338 18.4336 22.018 18.4336H27.182C27.4662 18.4336 27.7387 18.3207 27.9397 18.1197C28.1406 17.9188 28.2535 17.6462 28.2535 17.3621C28.2535 17.0779 28.1406 16.8053 27.9397 16.6044C27.7387 16.4034 27.4662 16.2906 27.182 16.2906Z" fill="black"/>
+</g>
+<defs>
+<clipPath id="clip0_5437_79067">
+<rect width="27" height="32" fill="white" transform="translate(7 4)"/>
+</clipPath>
+</defs>
+</svg>

Plik diff jest za duży
+ 0 - 7
packages/ui/src/assets/icons/app/iterm2.svg


+ 14 - 1
packages/ui/src/assets/icons/app/powershell.svg

@@ -1 +1,14 @@
-<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 128 128"><linearGradient id="powershell__a" x1="96.306" x2="25.454" y1="35.144" y2="98.431" gradientTransform="matrix(1 0 0 -1 0 128)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#a9c8ff"/><stop offset="1" stop-color="#c7e6ff"/></linearGradient><path fill="url(#powershell__a)" fill-rule="evenodd" d="M7.2 110.5c-1.7 0-3.1-.7-4.1-1.9-1-1.2-1.3-2.9-.9-4.6l18.6-80.5c.8-3.4 4-6 7.4-6h92.6c1.7 0 3.1.7 4.1 1.9 1 1.2 1.3 2.9.9 4.6l-18.6 80.5c-.8 3.4-4 6-7.4 6H7.2z" clip-rule="evenodd" opacity=".8"/><linearGradient id="powershell__b" x1="25.336" x2="94.569" y1="98.33" y2="36.847" gradientTransform="matrix(1 0 0 -1 0 128)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#2d4664"/><stop offset=".169" stop-color="#29405b"/><stop offset=".445" stop-color="#1e2f43"/><stop offset=".79" stop-color="#0c131b"/><stop offset="1"/></linearGradient><path fill="url(#powershell__b)" fill-rule="evenodd" d="M120.3 18.5H28.5c-2.9 0-5.7 2.3-6.4 5.2L3.7 104.3c-.7 2.9 1.1 5.2 4 5.2h91.8c2.9 0 5.7-2.3 6.4-5.2l18.4-80.5c.7-2.9-1.1-5.3-4-5.3z" clip-rule="evenodd"/><path fill="#2C5591" fill-rule="evenodd" d="M64.2 88.3h22.3c2.6 0 4.7 2.2 4.7 4.9s-2.1 4.9-4.7 4.9H64.2c-2.6 0-4.7-2.2-4.7-4.9s2.1-4.9 4.7-4.9zM78.7 66.5c-.4.8-1.2 1.6-2.6 2.6L34.6 98.9c-2.3 1.6-5.5 1-7.3-1.4-1.7-2.4-1.3-5.7.9-7.3l37.4-27.1v-.6l-23.5-25c-1.9-2-1.7-5.3.4-7.4 2.2-2 5.5-2 7.4 0l28.2 30c1.7 1.9 1.8 4.5.6 6.4z" clip-rule="evenodd"/><path fill="#FFF" fill-rule="evenodd" d="M77.6 65.5c-.4.8-1.2 1.6-2.6 2.6L33.6 97.9c-2.3 1.6-5.5 1-7.3-1.4-1.7-2.4-1.3-5.7.9-7.3l37.4-27.1v-.6l-23.5-25c-1.9-2-1.7-5.3.4-7.4 2.2-2 5.5-2 7.4 0l28.2 30c1.7 1.8 1.8 4.4.5 6.4zM63.5 87.8h22.3c2.6 0 4.7 2.1 4.7 4.6 0 2.6-2.1 4.6-4.7 4.6H63.5c-2.6 0-4.7-2.1-4.7-4.6 0-2.6 2.1-4.6 4.7-4.6z" clip-rule="evenodd"/></svg>
+<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M34.9013 7.2002H10.604C9.83641 7.2002 9.09532 7.84723 8.91004 8.66305L4.03999 31.3373C3.85472 32.1532 4.33113 32.8002 5.0987 32.8002H29.396C30.1636 32.8002 30.9047 32.1532 31.09 31.3373L35.96 8.69118C36.1453 7.87536 35.6689 7.2002 34.9013 7.2002Z" fill="url(#paint0_linear_5437_79143)"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M19.7489 26.5009H25.2421C25.8826 26.5009 26.3999 27.0942 26.3999 27.8223C26.3999 28.5505 25.8826 29.1438 25.2421 29.1438H19.7489C19.1085 29.1438 18.5912 28.5505 18.5912 27.8223C18.5912 27.0942 19.1085 26.5009 19.7489 26.5009ZM23.3208 20.6216C23.2222 20.8374 23.0252 21.0531 22.6803 21.3228L12.4575 29.3596C11.8909 29.7911 11.1027 29.6293 10.6593 28.982C10.2405 28.3347 10.339 27.4448 10.881 27.0133L20.0938 19.7047V19.5429L14.305 12.8006C13.837 12.2612 13.8862 11.3713 14.4035 10.8049C14.9455 10.2655 15.7584 10.2655 16.2264 10.8049L23.173 18.8956C23.5917 19.408 23.6163 20.1092 23.3208 20.6216Z" fill="#2C5591"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M23.2368 20.6216C23.1387 20.8374 22.9426 21.0531 22.5993 21.3228L12.448 29.3596C11.8841 29.7911 11.0994 29.6293 10.6581 28.982C10.2412 28.3347 10.3393 27.4448 10.8788 27.0133L20.0492 19.7047V19.5429L14.287 12.8006C13.8212 12.2612 13.8702 11.3713 14.3851 10.8049C14.9246 10.2655 15.7337 10.2655 16.1996 10.8049L23.1142 18.8956C23.5311 19.3811 23.5556 20.0822 23.2368 20.6216ZM19.7795 26.6357H25.2475C25.885 26.6357 26.3999 27.202 26.3999 27.8763C26.3999 28.5775 25.885 29.1168 25.2475 29.1168H19.7795C19.142 29.1168 18.6271 28.5505 18.6271 27.8763C18.6271 27.1751 19.142 26.6357 19.7795 26.6357Z" fill="white"/>
+<defs>
+<linearGradient id="paint0_linear_5437_79143" x1="9.76654" y1="10.3425" x2="29.068" y2="26.4694" gradientUnits="userSpaceOnUse">
+<stop stop-color="#2D4664"/>
+<stop offset="0.169" stop-color="#29405B"/>
+<stop offset="0.445" stop-color="#1E2F43"/>
+<stop offset="0.79" stop-color="#0C131B"/>
+<stop offset="1"/>
+</linearGradient>
+</defs>
+</svg>

+ 17 - 1
packages/ui/src/assets/icons/app/sublimetext.svg

@@ -1 +1,17 @@
-<svg viewBox="0 0 256 332" width="256" height="332" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid"><defs><linearGradient x1="55.117%" y1="58.68%" x2="63.68%" y2="39.597%" id="sublimetext__a"><stop stop-color="#FF9700" offset="0%"/><stop stop-color="#F48E00" offset="53%"/><stop stop-color="#D06F00" offset="100%"/></linearGradient></defs><path d="M255.288 166.795c0-3.887-2.872-6.128-6.397-5.015L6.397 238.675C2.865 239.796 0 243.86 0 247.74v78.59c0 3.887 2.865 6.135 6.397 5.015l242.494-76.888c3.525-1.12 6.397-5.185 6.397-9.071v-78.59Z" fill="url(#sublimetext__a)"/><path d="M0 164.291c0 3.887 2.865 7.95 6.397 9.071l242.53 76.902c3.531 1.12 6.397-1.127 6.397-5.007V166.66c0-3.88-2.866-7.944-6.397-9.064L6.397 80.694C2.865 79.574 0 81.814 0 85.7v78.59Z" fill="#FF9800"/><path d="M255.288 5.302c0-3.886-2.872-6.135-6.397-5.014L6.397 77.176C2.865 78.296 0 82.36 0 86.247v78.59c0 3.887 2.865 6.128 6.397 5.014l242.494-76.895c3.525-1.12 6.397-5.184 6.397-9.064V5.302Z" fill="#FF9800"/></svg>
+<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_5436_78897)">
+<path d="M35.911 20.0773C35.911 19.7026 35.552 19.4866 35.1114 19.5939L4.79962 27.0055C4.35812 27.1135 4 27.5052 4 27.8792V35.4541C4 35.8288 4.35812 36.0455 4.79962 35.9375L35.1114 28.5266C35.552 28.4187 35.911 28.0269 35.911 27.6523V20.0774V20.0773Z" fill="url(#paint0_linear_5436_78897)"/>
+<path d="M4 19.8353C4 20.21 4.35812 20.6016 4.79962 20.7097L35.1159 28.1219C35.5573 28.2299 35.9155 28.0133 35.9155 27.6393V20.0637C35.9155 19.6897 35.5573 19.298 35.1159 19.19L4.79962 11.7778C4.35812 11.6699 4 11.8858 4 12.2603V19.8353V19.8353Z" fill="#FF9800"/>
+<path d="M35.911 4.51106C35.911 4.1365 35.552 3.91973 35.1114 4.02778L4.79962 11.4387C4.35812 11.5466 4 11.9383 4 12.313V19.8879C4 20.2626 4.35812 20.4786 4.79962 20.3712L35.1114 12.9596C35.552 12.8517 35.911 12.46 35.911 12.086V4.51106Z" fill="#FF9800"/>
+</g>
+<defs>
+<linearGradient id="paint0_linear_5436_78897" x1="1762.84" y1="981.852" x2="1845.15" y2="624.882" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FF9700"/>
+<stop offset="0.53" stop-color="#F48E00"/>
+<stop offset="1" stop-color="#D06F00"/>
+</linearGradient>
+<clipPath id="clip0_5436_78897">
+<rect width="32" height="32" fill="white" transform="translate(4 4)"/>
+</clipPath>
+</defs>
+</svg>

BIN
packages/ui/src/assets/icons/app/terminal.png


BIN
packages/ui/src/assets/icons/app/textmate.png


Plik diff jest za duży
+ 0 - 0
packages/ui/src/assets/icons/app/vscode.svg


BIN
packages/ui/src/assets/icons/app/warp.png


BIN
packages/ui/src/assets/icons/app/xcode.png


+ 14 - 14
packages/ui/src/assets/icons/app/zed-dark.svg

@@ -1,15 +1,15 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" fill="none" viewBox="0 0 96 96">
-  <g clip-path="url(#zed_logo-dark-a)">
-    <path
-      fill="#fff"
-      fill-rule="evenodd"
-      d="M9 6a3 3 0 0 0-3 3v66H0V9a9 9 0 0 1 9-9h80.379c4.009 0 6.016 4.847 3.182 7.682L43.055 57.187H57V51h6v7.688a4.5 4.5 0 0 1-4.5 4.5H37.055L26.743 73.5H73.5V36h6v37.5a6 6 0 0 1-6 6H20.743L10.243 90H87a3 3 0 0 0 3-3V21h6v66a9 9 0 0 1-9 9H6.621c-4.009 0-6.016-4.847-3.182-7.682L52.757 39H39v6h-6v-7.5a4.5 4.5 0 0 1 4.5-4.5h21.257l10.5-10.5H22.5V60h-6V22.5a6 6 0 0 1 6-6h52.757L85.757 6H9Z"
-      clip-rule="evenodd"
-    />
-  </g>
-  <defs>
-    <clipPath id="zed_logo-dark-a">
-      <path fill="#fff" d="M0 0h96v96H0z" />
-    </clipPath>
-  </defs>
+<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_5437_79100)">
+<mask id="mask0_5437_79100" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="5" y="5" width="30" height="30">
+<path d="M5.6001 5.59961H34.4001V34.3996H5.6001V5.59961Z" fill="white"/>
+</mask>
+<g mask="url(#mask0_5437_79100)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8.3001 7.39961C8.0614 7.39961 7.83248 7.49443 7.6637 7.66321C7.49492 7.832 7.4001 8.06091 7.4001 8.29961V28.0996H5.6001V8.29961C5.6001 7.58352 5.88456 6.89677 6.39091 6.39042C6.89726 5.88407 7.58401 5.59961 8.3001 5.59961H32.4138C33.6165 5.59961 34.2186 7.05371 33.3684 7.90421L18.5166 22.7557H22.7001V20.8996H24.5001V23.206C24.5001 23.5641 24.3579 23.9074 24.1047 24.1606C23.8515 24.4138 23.5081 24.556 23.1501 24.556H16.7166L13.623 27.6496H27.6501V16.3996H29.4501V27.6496C29.4501 28.127 29.2605 28.5848 28.9229 28.9224C28.5853 29.26 28.1275 29.4496 27.6501 29.4496H11.823L8.673 32.5996H31.7001C31.9388 32.5996 32.1677 32.5048 32.3365 32.336C32.5053 32.1672 32.6001 31.9383 32.6001 31.6996V11.8996H34.4001V31.6996C34.4001 32.4157 34.1156 33.1024 33.6093 33.6088C33.1029 34.1151 32.4162 34.3996 31.7001 34.3996H7.5864C6.3837 34.3996 5.7816 32.9455 6.6318 32.095L21.4272 17.2996H17.3001V19.0996H15.5001V16.8496C15.5001 16.4916 15.6423 16.1482 15.8955 15.895C16.1487 15.6418 16.4921 15.4996 16.8501 15.4996H23.2272L26.3772 12.3496H12.3501V23.5996H10.5501V12.3496C10.5501 11.8722 10.7397 11.4144 11.0773 11.0768C11.4149 10.7393 11.8727 10.5496 12.3501 10.5496H28.1772L31.3272 7.39961H8.3001Z" fill="white"/>
+</g>
+</g>
+<defs>
+<clipPath id="clip0_5437_79100">
+<rect width="28.8" height="28.8" fill="white" transform="translate(5.6001 5.59961)"/>
+</clipPath>
+</defs>
 </svg>

+ 14 - 14
packages/ui/src/assets/icons/app/zed.svg

@@ -1,15 +1,15 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" fill="none" viewBox="0 0 96 96">
-  <g clip-path="url(#zed_logo-a)">
-    <path
-      fill="#000"
-      fill-rule="evenodd"
-      d="M9 6a3 3 0 0 0-3 3v66H0V9a9 9 0 0 1 9-9h80.379c4.009 0 6.016 4.847 3.182 7.682L43.055 57.187H57V51h6v7.688a4.5 4.5 0 0 1-4.5 4.5H37.055L26.743 73.5H73.5V36h6v37.5a6 6 0 0 1-6 6H20.743L10.243 90H87a3 3 0 0 0 3-3V21h6v66a9 9 0 0 1-9 9H6.621c-4.009 0-6.016-4.847-3.182-7.682L52.757 39H39v6h-6v-7.5a4.5 4.5 0 0 1 4.5-4.5h21.257l10.5-10.5H22.5V60h-6V22.5a6 6 0 0 1 6-6h52.757L85.757 6H9Z"
-      clip-rule="evenodd"
-    />
-  </g>
-  <defs>
-    <clipPath id="zed_logo-a">
-      <path fill="#fff" d="M0 0h96v96H0z" />
-    </clipPath>
-  </defs>
+<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_5437_79109)">
+<mask id="mask0_5437_79109" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="5" y="5" width="30" height="30">
+<path d="M5.6001 5.59961H34.4001V34.3996H5.6001V5.59961Z" fill="white"/>
+</mask>
+<g mask="url(#mask0_5437_79109)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8.3001 7.39961C8.0614 7.39961 7.83248 7.49443 7.6637 7.66321C7.49492 7.832 7.4001 8.06091 7.4001 8.29961V28.0996H5.6001V8.29961C5.6001 7.58352 5.88456 6.89677 6.39091 6.39042C6.89726 5.88407 7.58401 5.59961 8.3001 5.59961H32.4138C33.6165 5.59961 34.2186 7.05371 33.3684 7.90421L18.5166 22.7557H22.7001V20.8996H24.5001V23.206C24.5001 23.5641 24.3579 23.9074 24.1047 24.1606C23.8515 24.4138 23.5081 24.556 23.1501 24.556H16.7166L13.623 27.6496H27.6501V16.3996H29.4501V27.6496C29.4501 28.127 29.2605 28.5848 28.9229 28.9224C28.5853 29.26 28.1275 29.4496 27.6501 29.4496H11.823L8.673 32.5996H31.7001C31.9388 32.5996 32.1677 32.5048 32.3365 32.336C32.5053 32.1672 32.6001 31.9383 32.6001 31.6996V11.8996H34.4001V31.6996C34.4001 32.4157 34.1156 33.1024 33.6093 33.6088C33.1029 34.1151 32.4162 34.3996 31.7001 34.3996H7.5864C6.3837 34.3996 5.7816 32.9455 6.6318 32.095L21.4272 17.2996H17.3001V19.0996H15.5001V16.8496C15.5001 16.4916 15.6423 16.1482 15.8955 15.895C16.1487 15.6418 16.4921 15.4996 16.8501 15.4996H23.2272L26.3772 12.3496H12.3501V23.5996H10.5501V12.3496C10.5501 11.8722 10.7397 11.4144 11.0773 11.0768C11.4149 10.7393 11.8727 10.5496 12.3501 10.5496H28.1772L31.3272 7.39961H8.3001Z" fill="black"/>
+</g>
+</g>
+<defs>
+<clipPath id="clip0_5437_79109">
+<rect width="28.8" height="28.8" fill="white" transform="translate(5.6001 5.59961)"/>
+</clipPath>
+</defs>
 </svg>

+ 12 - 0
packages/ui/src/components/button.css

@@ -180,3 +180,15 @@
 [data-component="button"].titlebar-icon[data-variant="ghost"][aria-expanded="true"]:hover:not(:disabled) {
   background-color: var(--surface-base-active);
 }
+
+[data-component="button"].titlebar-icon[data-variant="ghost"][aria-current="page"] {
+  background-color: var(--surface-base-active);
+}
+
+[data-component="button"].titlebar-icon[data-variant="ghost"][aria-current="page"] [data-slot="icon-svg"] {
+  color: var(--icon-strong-base);
+}
+
+[data-component="button"].titlebar-icon[data-variant="ghost"][aria-current="page"]:hover:not(:disabled) {
+  background-color: var(--surface-base-active);
+}

+ 10 - 0
packages/ui/src/components/dropdown-menu.css

@@ -58,6 +58,11 @@
     }
   }
 
+  [data-slot="dropdown-menu-checkbox-item"],
+  [data-slot="dropdown-menu-radio-item"] {
+    padding-right: 28px;
+  }
+
   [data-slot="dropdown-menu-sub-trigger"] {
     &[data-expanded] {
       background: var(--surface-raised-base-hover);
@@ -70,6 +75,10 @@
     justify-content: center;
     width: 16px;
     height: 16px;
+    position: absolute;
+    right: 8px;
+    top: 50%;
+    transform: translateY(-50%);
   }
 
   [data-slot="dropdown-menu-item-label"] {
@@ -88,6 +97,7 @@
   }
 
   [data-slot="dropdown-menu-group-label"] {
+    display: block;
     padding: 4px 8px;
     font-family: var(--font-family-sans);
     font-size: var(--font-size-x-small);

+ 19 - 3
packages/ui/src/components/icon.tsx

@@ -22,6 +22,12 @@ const icons = {
   "close-small": `<path d="M6 6L14 14M14 6L6 14" stroke="currentColor" stroke-linecap="square"/>`,
   checklist: `<path d="M9.58342 13.7498H17.0834M9.58342 6.24984H17.0834M2.91675 6.6665L4.58341 7.9165L7.08341 4.1665M2.91675 14.1665L4.58341 15.4165L7.08341 11.6665" stroke="currentColor" stroke-linecap="square"/>`,
   console: `<path d="M3.75 5.4165L8.33333 9.99984L3.75 14.5832M10.4167 14.5832H16.25" stroke="currentColor" stroke-linecap="square"/>`,
+  terminal: `<path d="M6.5 8L8.64286 10L6.5 12M10.9286 12H13.5M2 18H18V2H2V18Z" stroke="currentColor" stroke-linecap="square"/>`,
+  "terminal-active": `<path d="M2 18H18V2H2V18Z" fill="currentColor" fill-opacity="0.1"/>
+<path d="M6.5 8L8.64286 10L6.5 12M10.9286 12H13.5M2 18H18V2H2V18Z" stroke="currentColor" stroke-linecap="square"/>`,
+  review: `<path d="M7 14.5H13M7 7.99512H10.0049M10.0049 7.99512H13M10.0049 7.99512V5M10.0049 7.99512V11M18 18V2L2 2L2 18H18Z" stroke="currentColor"/>`,
+  "review-active": `<path d="M18 18V2L2 2L2 18H18Z" fill="currentColor" fill-opacity="0.1"/>
+<path d="M7 14.5H13M7 7.99512H10.0049M10.0049 7.99512H13M10.0049 7.99512V5M10.0049 7.99512V11M18 18V2L2 2L2 18H18Z" stroke="currentColor"/>`,
   expand: `<path d="M4.58301 10.4163V15.4163H9.58301M10.4163 4.58301H15.4163V9.58301" stroke="currentColor" stroke-linecap="square"/>`,
   collapse: `<path d="M16.666 8.33398H11.666V3.33398" stroke="currentColor" stroke-linecap="square"/><path d="M8.33398 16.666V11.666H3.33398" stroke="currentColor" stroke-linecap="square"/>`,
   code: `<path d="M8.7513 7.5013L6.2513 10.0013L8.7513 12.5013M11.2513 7.5013L13.7513 10.0013L11.2513 12.5013M2.91797 2.91797H17.0846V17.0846H2.91797V2.91797Z" stroke="currentColor"/>`,
@@ -31,12 +37,15 @@ const icons = {
   eye: `<path d="M10 4.58325C5.83333 4.58325 2.5 9.99992 2.5 9.99992C2.5 9.99992 5.83333 15.4166 10 15.4166C14.1667 15.4166 17.5 9.99992 17.5 9.99992C17.5 9.99992 14.1667 4.58325 10 4.58325Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/><circle cx="10" cy="10" r="2.5" stroke="currentColor"/>`,
   enter: `<path d="M5.83333 15.8334L2.5 12.5L5.83333 9.16671M3.33333 12.5H17.9167V4.58337H10" stroke="currentColor" stroke-linecap="square"/>`,
   folder: `<path d="M2.08301 2.91675V16.2501H17.9163V5.41675H9.99967L8.33301 2.91675H2.08301Z" stroke="currentColor" stroke-linecap="round"/>`,
-  "file-tree": `<path d="M4.58203 16.6693L6.66536 9.58594H17.082M4.58203 16.6693H16.457L18.5404 9.58594H17.082M4.58203 16.6693H2.08203V3.33594H8.33203L9.9987 5.83594H17.082V9.58594" stroke="currentColor" stroke-linecap="round"/>`,
-  "file-tree-active": `<path d="M6.66536 9.58594L4.58203 16.6693H16.457L18.5404 9.58594H17.082H6.66536Z" fill="currentColor" fill-opacity="16%"/><path d="M4.58203 16.6693L6.66536 9.58594H17.082M4.58203 16.6693H16.457L18.5404 9.58594H17.082M4.58203 16.6693H2.08203V3.33594H8.33203L9.9987 5.83594H17.082V9.58594" stroke="currentColor" stroke-linecap="round"/>`,
+  "file-tree": `<path d="M18 18V5H9.5L7.5 2H2L2 18H5M18 18H5M18 18V8.5H5V18" stroke="currentColor" stroke-linecap="square"/>`,
+  "file-tree-active": `<path d="M2 2L2 18H5L6.5 8.5H18V5H9.5L7.5 2H2Z" fill="currentColor" fill-opacity="0.1"/>
+<path d="M5 18H18L19.5 8.5H18M5 18H2L2 2H7.5L9.5 5H18V8.5M5 18L6.5 8.5H18" stroke="currentColor" stroke-linecap="square"/>`,
   "magnifying-glass": `<path d="M13 13L10.6418 10.6418M11.9552 7.47761C11.9552 9.95053 9.95053 11.9552 7.47761 11.9552C5.0047 11.9552 3 9.95053 3 7.47761C3 5.0047 5.0047 3 7.47761 3C9.95053 3 11.9552 5.0047 11.9552 7.47761Z" stroke="currentColor" stroke-linecap="square" vector-effect="non-scaling-stroke"/>`,
   "plus-small": `<path d="M9.99984 5.41699V10.0003M9.99984 10.0003V14.5837M9.99984 10.0003H5.4165M9.99984 10.0003H14.5832" stroke="currentColor" stroke-linecap="square"/>`,
   plus: `<path d="M9.9987 2.20703V9.9987M9.9987 9.9987V17.7904M9.9987 9.9987H2.20703M9.9987 9.9987H17.7904" stroke="currentColor" stroke-linecap="square"/>`,
-  "new-session": `<path d="M17.0827 17.0807V17.5807H17.5827V17.0807H17.0827ZM2.91602 17.0807H2.41602L2.41602 17.5807H2.91602L2.91602 17.0807ZM2.91602 2.91406V2.41406H2.41602V2.91406H2.91602ZM9.58268 3.41406H10.0827V2.41406L9.58268 2.41406V2.91406V3.41406ZM17.5827 10.4141V9.91406L16.5827 9.91406V10.4141H17.0827H17.5827ZM6.24935 11.2474L5.8958 10.8938L5.74935 11.0403V11.2474H6.24935ZM6.24935 13.7474H5.74935V14.2474H6.24935V13.7474ZM8.74935 13.7474V14.2474H8.95646L9.1029 14.101L8.74935 13.7474ZM15.2077 2.28906L15.5612 1.93551L15.2077 1.58196L14.8541 1.93551L15.2077 2.28906ZM17.7077 4.78906L18.0612 5.14262L18.4148 4.78906L18.0612 4.43551L17.7077 4.78906ZM17.0827 17.0807V16.5807H2.91602V17.0807L2.91602 17.5807H17.0827V17.0807ZM2.91602 17.0807H3.41602L3.41602 2.91406H2.91602H2.41602L2.41602 17.0807H2.91602ZM2.91602 2.91406V3.41406L9.58268 3.41406V2.91406V2.41406L2.91602 2.41406V2.91406ZM17.0827 10.4141H16.5827V17.0807H17.0827H17.5827V10.4141H17.0827ZM6.24935 11.2474H5.74935V13.7474H6.24935H6.74935V11.2474H6.24935ZM6.24935 13.7474V14.2474L8.74935 14.2474V13.7474V13.2474L6.24935 13.2474V13.7474ZM6.24935 11.2474L6.6029 11.6009L15.5612 2.64262L15.2077 2.28906L14.8541 1.93551L5.8958 10.8938L6.24935 11.2474ZM15.2077 2.28906L14.8541 2.64262L17.3541 5.14262L17.7077 4.78906L18.0612 4.43551L15.5612 1.93551L15.2077 2.28906ZM17.7077 4.78906L17.3541 4.43551L8.3958 13.3938L8.74935 13.7474L9.1029 14.101L18.0612 5.14262L17.7077 4.78906Z" fill="currentColor"/>`,
+  "new-session": `<path d="M12 2H2V18H18V8M6 11.3818V14H8.61818L18 4.61818L15.3818 2L6 11.3818Z" stroke="currentColor"/>`,
+  "new-session-active": `<path d="M6 11.3818V14H8.61818L18 4.61818L15.3818 2L6 11.3818Z" fill="currentColor" fill-opacity="0.1"/>
+<path d="M12 2H2V18H18V8M6 11.3818V14H8.61818L18 4.61818L15.3818 2L6 11.3818Z" stroke="currentColor"/>`,
   "pencil-line": `<path d="M9.58301 17.9166H17.9163M17.9163 5.83325L14.1663 2.08325L2.08301 14.1666V17.9166H5.83301L17.9163 5.83325Z" stroke="currentColor" stroke-linecap="square"/>`,
   mcp: `<g><path d="M0.972656 9.37176L9.5214 1.60019C10.7018 0.527151 12.6155 0.527151 13.7957 1.60019C14.9761 2.67321 14.9761 4.41295 13.7957 5.48599L7.3397 11.3552" stroke="currentColor" stroke-linecap="round"/><path d="M7.42871 11.2747L13.7957 5.48643C14.9761 4.41338 16.8898 4.41338 18.0702 5.48643L18.1147 5.52688C19.2951 6.59993 19.2951 8.33966 18.1147 9.4127L10.3831 16.4414C9.98966 16.7991 9.98966 17.379 10.3831 17.7366L11.9707 19.1799" stroke="currentColor" stroke-linecap="round"/><path d="M11.6587 3.54346L5.33619 9.29119C4.15584 10.3642 4.15584 12.1039 5.33619 13.177C6.51649 14.25 8.43019 14.25 9.61054 13.177L15.9331 7.42923" stroke="currentColor" stroke-linecap="round"/></g>`,
   glasses: `<path d="M0.416626 7.91667H1.66663M19.5833 7.91667H18.3333M11.866 7.57987C11.3165 7.26398 10.6793 7.08333 9.99996 7.08333C9.32061 7.08333 8.68344 7.26398 8.13389 7.57987M8.74996 10C8.74996 12.0711 7.07103 13.75 4.99996 13.75C2.92889 13.75 1.24996 12.0711 1.24996 10C1.24996 7.92893 2.92889 6.25 4.99996 6.25C7.07103 6.25 8.74996 7.92893 8.74996 10ZM18.75 10C18.75 12.0711 17.071 13.75 15 13.75C12.9289 13.75 11.25 12.0711 11.25 10C11.25 7.92893 12.9289 6.25 15 6.25C17.071 6.25 18.75 7.92893 18.75 10Z" stroke="currentColor" stroke-linecap="square"/>`,
@@ -44,6 +53,13 @@ const icons = {
   "window-cursor": `<path d="M17.9166 10.4167V3.75H2.08325V17.0833H10.4166M17.9166 13.5897L11.6666 11.6667L13.5897 17.9167L15.032 15.0321L17.9166 13.5897Z" stroke="currentColor" stroke-width="1.07143" stroke-linecap="square"/><path d="M5.00024 6.125C5.29925 6.12518 5.54126 6.36795 5.54126 6.66699C5.54108 6.96589 5.29914 7.20783 5.00024 7.20801C4.7012 7.20801 4.45843 6.966 4.45825 6.66699C4.45825 6.36784 4.70109 6.125 5.00024 6.125ZM7.91626 6.125C8.21541 6.125 8.45825 6.36784 8.45825 6.66699C8.45808 6.966 8.21531 7.20801 7.91626 7.20801C7.61736 7.20783 7.37542 6.96589 7.37524 6.66699C7.37524 6.36795 7.61726 6.12518 7.91626 6.125ZM10.8333 6.125C11.1324 6.125 11.3752 6.36784 11.3752 6.66699C11.3751 6.966 11.1323 7.20801 10.8333 7.20801C10.5342 7.20801 10.2914 6.966 10.2913 6.66699C10.2913 6.36784 10.5341 6.125 10.8333 6.125Z" fill="currentColor" stroke="currentColor" stroke-width="0.25" stroke-linecap="square"/>`,
   task: `<path d="M9.99992 2.0835V17.9168M7.08325 3.75016H2.08325V16.2502H7.08325M12.9166 16.2502H17.9166V3.75016H12.9166" stroke="currentColor" stroke-linecap="square"/>`,
   stop: `<rect x="5" y="5" width="10" height="10" fill="currentColor"/>`,
+  status: `<path d="M2 10V18H18V10M2 10V2H18V10M2 10H18M5 6H9M5 14H9" stroke="currentColor"/>`,
+  "status-active": `<path d="M18 2H2V10H18V2Z" fill="currentColor" fill-opacity="0.1"/>
+<path d="M2 18H18V10H2V18Z" fill="currentColor" fill-opacity="0.1"/>
+<path d="M2 10V18H18V10M2 10V2H18V10M2 10H18M5 6H9M5 14H9" stroke="currentColor"/>`,
+  sidebar: `<path d="M7.86667 2H5.2H2V18H5.2H7.86667M7.86667 2H18V18H7.86667M7.86667 2V18" stroke="currentColor"/>`,
+  "sidebar-active": `<path d="M2 2V18H5.2H7.86667V2H5.2H2Z" fill="currentColor" fill-opacity="0.1"/>
+<path d="M7.86667 2H5.2H2V18H5.2H7.86667M7.86667 2H18V18H7.86667M7.86667 2V18" stroke="currentColor"/>`,
   "layout-left": `<path d="M2.91675 2.91699L2.91675 2.41699L2.41675 2.41699L2.41675 2.91699L2.91675 2.91699ZM17.0834 2.91699L17.5834 2.91699L17.5834 2.41699L17.0834 2.41699L17.0834 2.91699ZM17.0834 17.0837L17.0834 17.5837L17.5834 17.5837L17.5834 17.0837L17.0834 17.0837ZM2.91675 17.0837L2.41675 17.0837L2.41675 17.5837L2.91675 17.5837L2.91675 17.0837ZM7.41674 17.0837L7.41674 17.5837L8.41674 17.5837L8.41674 17.0837L7.91674 17.0837L7.41674 17.0837ZM8.41674 2.91699L8.41674 2.41699L7.41674 2.41699L7.41674 2.91699L7.91674 2.91699L8.41674 2.91699ZM2.91675 2.91699L2.91675 3.41699L17.0834 3.41699L17.0834 2.91699L17.0834 2.41699L2.91675 2.41699L2.91675 2.91699ZM17.0834 2.91699L16.5834 2.91699L16.5834 17.0837L17.0834 17.0837L17.5834 17.0837L17.5834 2.91699L17.0834 2.91699ZM17.0834 17.0837L17.0834 16.5837L2.91675 16.5837L2.91675 17.0837L2.91675 17.5837L17.0834 17.5837L17.0834 17.0837ZM2.91675 17.0837L3.41675 17.0837L3.41675 2.91699L2.91675 2.91699L2.41675 2.91699L2.41675 17.0837L2.91675 17.0837ZM7.91674 17.0837L8.41674 17.0837L8.41674 2.91699L7.91674 2.91699L7.41674 2.91699L7.41674 17.0837L7.91674 17.0837Z" fill="currentColor"/>`,
   "layout-left-partial": `<path d="M2.91732 2.91602L7.91732 2.91602L7.91732 17.0827H2.91732L2.91732 2.91602Z" fill="currentColor" fill-opacity="16%" /><path d="M2.91732 2.91602L17.084 2.91602M2.91732 2.91602L2.91732 17.0827M2.91732 2.91602L7.91732 2.91602M17.084 2.91602L17.084 17.0827M17.084 2.91602L7.91732 2.91602M17.084 17.0827L2.91732 17.0827M17.084 17.0827L7.91732 17.0827M2.91732 17.0827H7.91732M7.91732 17.0827L7.91732 2.91602" stroke="currentColor" stroke-linecap="square"/>`,
   "layout-left-full": `<path d="M2.91732 2.91602L7.91732 2.91602L7.91732 17.0827H2.91732L2.91732 2.91602Z" fill="currentColor"/><path d="M2.91732 2.91602L17.084 2.91602M2.91732 2.91602L2.91732 17.0827M2.91732 2.91602L7.91732 2.91602M17.084 2.91602L17.084 17.0827M17.084 2.91602L7.91732 2.91602M17.084 17.0827L2.91732 17.0827M17.084 17.0827L7.91732 17.0827M2.91732 17.0827H7.91732M7.91732 17.0827L7.91732 2.91602" stroke="currentColor" stroke-linecap="square"/>`,

+ 2 - 1
packages/ui/src/components/message-part.css

@@ -614,7 +614,7 @@
   align-items: center;
   justify-content: flex-start;
   gap: 0px;
-  cursor: pointer;
+  cursor: default;
 
   [data-slot="context-tool-group-title"] {
     flex-shrink: 1;
@@ -623,6 +623,7 @@
 
   [data-slot="collapsible-arrow"] {
     color: var(--icon-weaker);
+    cursor: pointer;
   }
 }
 

+ 5 - 0
packages/ui/src/styles/tailwind/utilities.css

@@ -13,6 +13,11 @@
   mask-image: radial-gradient(circle 5px at calc(100% - 4px) 4px, transparent 5px, black 5.5px);
 }
 
+@utility badge-mask-tight {
+  -webkit-mask-image: radial-gradient(circle 5px at calc(100% - 2px) 2px, transparent 5px, black 5.5px);
+  mask-image: radial-gradient(circle 5px at calc(100% - 2px) 2px, transparent 5px, black 5.5px);
+}
+
 @utility truncate-start {
   text-overflow: ellipsis;
   overflow: hidden;

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików