diff --git a/docs/docs/ai-presets.mdx b/docs/docs/ai-presets.mdx
index 8d1dc2a47..e822553b7 100644
--- a/docs/docs/ai-presets.mdx
+++ b/docs/docs/ai-presets.mdx
@@ -4,12 +4,7 @@ id: "ai-presets"
title: "AI Presets"
---
-
+![AI Presets Menu](./img/ai-presets.png#right)
Wave's AI widget can be configured to work with various AI providers and models through presets. Presets allow you to define multiple AI configurations and easily switch between them using the dropdown menu in the AI widget.
diff --git a/docs/docs/config.mdx b/docs/docs/config.mdx
index 832ae5075..4815e6452 100644
--- a/docs/docs/config.mdx
+++ b/docs/docs/config.mdx
@@ -1,5 +1,5 @@
---
-sidebar_position: 3
+sidebar_position: 3.45
id: "config"
title: "Configuration"
---
diff --git a/docs/docs/connections.mdx b/docs/docs/connections.mdx
index 88afc576a..914b72d92 100644
--- a/docs/docs/connections.mdx
+++ b/docs/docs/connections.mdx
@@ -1,5 +1,5 @@
---
-sidebar_position: 7
+sidebar_position: 3.1
id: "connections"
title: "Connections"
---
@@ -12,7 +12,7 @@ Wave allows users to connect to various machines and unify them together in a wa
The easiest way to access connections is to click the icon. From there, you can either type `[user]@[host]` for a desired SSH remote or type `wsl://` for a desired WSL distribution. Alternatively, if the connection already exists in the dropdown list, you can either click it or navigate to it with arrow keys and press enter to connect.
-![a dropdown showing a list of connections that already exist](/img/connection-dropdown.png)
+![a dropdown showing a list of connections that already exist](./img/connection-dropdown.png)
## What are wsh Shell Extensions?
diff --git a/docs/docs/customization.mdx b/docs/docs/customization.mdx
index 9a452acb7..ed290d0a6 100644
--- a/docs/docs/customization.mdx
+++ b/docs/docs/customization.mdx
@@ -1,35 +1,23 @@
---
-sidebar_position: 1.5
+sidebar_position: 3.2
id: "customization"
title: "Customization"
---
## Tab Themes
-
+![Tab Context Menu](./img/tab-context-menu.png#right)
Right click on any tab to bring up a menu which allows you to rename the tab and select different backgrounds.
It is also possible to create your own themes using custom colors, gradients, images and more by editing your presets.json config file. To see how Wave's built in tab themes are defined, you can check out our [default presets file](https://github.com/wavetermdev/waveterm/blob/main/pkg/wconfig/defaultconfig/presets.json).
-
-
## Terminal Customization
-
-
#### Terminal Theme
+![Terminal Context Menu](./img/terminal-context-menu.png#right)
+
Right click in the header area of any terminal block to bring up a menu which allows you to set a terminal
theme for that terminal.
@@ -40,8 +28,6 @@ If you add your own termthemes.json file in the config directory, you can also a
You can set the key `tab:preset` in your [Wave Config File](/config) to apply a theme to all new tabs.
-
-
#### Font Size
From the same context menu you can also change the font-size of the terminal. To change the default font size across all of your (non-overridden) terminals, you can set the config key `term:fontsize` to the size you want. e.g. `{ "term:fontsize": 14}`.
@@ -52,12 +38,7 @@ There is no UI to edit your default terminal font family. But, it _can_ be overr
## Widgets Sidebar
-
+![Terminal Context Menu](./img/custom-widgets.png#right)
See [Custom Widgets](/customwidgets) for detailed documentation around changing what appears in your right widget sidebar.
@@ -65,8 +46,6 @@ Using widgets.json, you'll be able to remove any default widgets and add widgets
You can also suppress the help widgets in the bottom right by setting the config key `widget:showhelp` to `false`.
-
-
## Tab Backgrounds
Wave supports powerful custom backgrounds for your tabs using images, patterns, gradients, and colors. The quickest way to set an image background is using the `wsh setbg` command:
diff --git a/docs/docs/customwidgets.mdx b/docs/docs/customwidgets.mdx
index 5896800ef..b04bd1491 100644
--- a/docs/docs/customwidgets.mdx
+++ b/docs/docs/customwidgets.mdx
@@ -7,11 +7,11 @@ title: "Custom Widgets"
# Custom Widgets
Wave allows users to create their own widgets to uniquely customize their experience for what works for them. While we plan on greatly expanding on this in the future, it is already possible to make some widgets that you can access at the press of a button. All widgets can be created by modifying the `/config/widgets.json` file. By adding a widget to this file, it is possible to add widgets to the widget bar. By default, the widget bar looks like this:
-![The default widget bar](/img/all-widgets-default.webp)
+![The default widget bar](./img/all-widgets-default.webp)
By adding additional widgets, it is possible to get a widget bar that looks like this:
-![A widget bar with custom widgets added](/img/all-widgets-extra.webp)
+![A widget bar with custom widgets added](./img/all-widgets-extra.webp)
## The Structure of a Widget
@@ -34,7 +34,7 @@ All widgets share a similar structure that roughly looks like the example below:
This consists of a couple different parts. First and foremost, each widget has a unique identifying name. The value associated with this name is the outer `WidgetConfigType`. It is outlined in red below:
-![An example of a widget with outer keys labeled as WidgetConfigType and inner keys labeled as MetaTSType. In the example, the outer keys are icon, label, color, and blockdef. The inner keys are view, controller, and cmd.](/img/widget-example.webp)
+![An example of a widget with outer keys labeled as WidgetConfigType and inner keys labeled as MetaTSType. In the example, the outer keys are icon, label, color, and blockdef. The inner keys are view, controller, and cmd.](./img/widget-example.webp)
This `WidgetConfigType` is shared between all types of widgets. That is to say, all widgets—regardless of type— will use the same keys for this. The accepted keys are:
@@ -135,7 +135,7 @@ Suppose I want a widget that will run speedtest-go when opened. Then, I can defi
```
This adds an icon to the widget bar that you can press to launch a terminal running the `speedtest-go --unix` command.
-![The example speedtest widget](/img/widget-example-speed.webp)
+![The example speedtest widget](./img/widget-example-speed.webp)
Using `"cmd"` for the `"controller"` is the simplest way to accomplish this. `"cmd:clearonstart"` isn't necessary, but it makes it so every time the command is run (which can be done by right clicking the header and selecting `Force Controller Restart`), the previous contents are cleared out.
@@ -158,7 +158,7 @@ Now suppose I wanted to run a TUI app, for instance, `dua`. Well, it turns out t
```
This adds an icon to the widget bar that you can press to launch a terminal running the `dua` command.
-![The example speedtest widget](/img/widget-example-dua.webp)
+![The example speedtest widget](./img/widget-example-dua.webp)
Because this is a TUI app that does not return anything when closed, the `"cmd:clearonstart"` option doesn't change the behavior, so it has been excluded.
@@ -212,7 +212,7 @@ Say you want a widget that automatically starts at YouTube and will use YouTube
```
This adds an icon to the widget bar that you can press to launch a web widget on the youtube homepage.
-![The example speedtest widget](/img/widget-example-youtube.webp)
+![The example speedtest widget](./img/widget-example-youtube.webp)
Alternatively, say you want a web widget that opens to github as if it were a bookmark, but will use google as its home page after that. This can easily be done with:
@@ -233,7 +233,7 @@ Alternatively, say you want a web widget that opens to github as if it were a bo
```
This adds an icon to the widget bar that you can press to launch a web widget on the github homepage.
-![The example speedtest widget](/img/widget-example-github.webp)
+![The example speedtest widget](./img/widget-example-github.webp)
# Sysinfo Widgets
@@ -286,7 +286,7 @@ Suppose you have a build process that lasts 3 minutes and you'd like to be able
```
This adds an icon to the widget bar that you can press to launch the CPU and Memory plots by default with 180 seconds of data.
-![The example speedtest widget](/img/widget-example-3mininfo.webp)
+![The example speedtest widget](./img/widget-example-3mininfo.webp)
Now, suppose you are fine with the default 100 points (and 100 seconds) but would like to show all of the CPU data when launched. In that case, you can write:
@@ -307,4 +307,4 @@ Now, suppose you are fine with the default 100 points (and 100 seconds) but woul
This adds an icon to the widget bar that you can press to launch All CPU plots by default.
-![The example speedtest widget](/img/widget-example-all-cpu.webp)
+![The example speedtest widget](./img/widget-example-all-cpu.webp)
diff --git a/docs/static/img/ai-presets.png b/docs/docs/img/ai-presets.png
similarity index 100%
rename from docs/static/img/ai-presets.png
rename to docs/docs/img/ai-presets.png
diff --git a/docs/static/img/all-widgets-default.png b/docs/docs/img/all-widgets-default.png
similarity index 100%
rename from docs/static/img/all-widgets-default.png
rename to docs/docs/img/all-widgets-default.png
diff --git a/docs/static/img/all-widgets-default.webp b/docs/docs/img/all-widgets-default.webp
similarity index 100%
rename from docs/static/img/all-widgets-default.webp
rename to docs/docs/img/all-widgets-default.webp
diff --git a/docs/static/img/all-widgets-extra.png b/docs/docs/img/all-widgets-extra.png
similarity index 100%
rename from docs/static/img/all-widgets-extra.png
rename to docs/docs/img/all-widgets-extra.png
diff --git a/docs/static/img/all-widgets-extra.webp b/docs/docs/img/all-widgets-extra.webp
similarity index 100%
rename from docs/static/img/all-widgets-extra.webp
rename to docs/docs/img/all-widgets-extra.webp
diff --git a/docs/static/img/connection-dropdown.png b/docs/docs/img/connection-dropdown.png
similarity index 100%
rename from docs/static/img/connection-dropdown.png
rename to docs/docs/img/connection-dropdown.png
diff --git a/docs/static/img/custom-widgets.png b/docs/docs/img/custom-widgets.png
similarity index 100%
rename from docs/static/img/custom-widgets.png
rename to docs/docs/img/custom-widgets.png
diff --git a/docs/static/img/tab-context-menu.png b/docs/docs/img/tab-context-menu.png
similarity index 100%
rename from docs/static/img/tab-context-menu.png
rename to docs/docs/img/tab-context-menu.png
diff --git a/docs/static/img/terminal-context-menu.png b/docs/docs/img/terminal-context-menu.png
similarity index 100%
rename from docs/static/img/terminal-context-menu.png
rename to docs/docs/img/terminal-context-menu.png
diff --git a/docs/static/img/wave-screenshot.webp b/docs/docs/img/wave-screenshot.webp
similarity index 100%
rename from docs/static/img/wave-screenshot.webp
rename to docs/docs/img/wave-screenshot.webp
diff --git a/docs/static/img/widget-example-3mininfo.webp b/docs/docs/img/widget-example-3mininfo.webp
similarity index 100%
rename from docs/static/img/widget-example-3mininfo.webp
rename to docs/docs/img/widget-example-3mininfo.webp
diff --git a/docs/static/img/widget-example-all-cpu.webp b/docs/docs/img/widget-example-all-cpu.webp
similarity index 100%
rename from docs/static/img/widget-example-all-cpu.webp
rename to docs/docs/img/widget-example-all-cpu.webp
diff --git a/docs/static/img/widget-example-dua.webp b/docs/docs/img/widget-example-dua.webp
similarity index 100%
rename from docs/static/img/widget-example-dua.webp
rename to docs/docs/img/widget-example-dua.webp
diff --git a/docs/static/img/widget-example-github.webp b/docs/docs/img/widget-example-github.webp
similarity index 100%
rename from docs/static/img/widget-example-github.webp
rename to docs/docs/img/widget-example-github.webp
diff --git a/docs/static/img/widget-example-speed.webp b/docs/docs/img/widget-example-speed.webp
similarity index 100%
rename from docs/static/img/widget-example-speed.webp
rename to docs/docs/img/widget-example-speed.webp
diff --git a/docs/static/img/widget-example-youtube.webp b/docs/docs/img/widget-example-youtube.webp
similarity index 100%
rename from docs/static/img/widget-example-youtube.webp
rename to docs/docs/img/widget-example-youtube.webp
diff --git a/docs/static/img/widget-example.webp b/docs/docs/img/widget-example.webp
similarity index 100%
rename from docs/static/img/widget-example.webp
rename to docs/docs/img/widget-example.webp
diff --git a/docs/docs/img/workspace-switcher.png b/docs/docs/img/workspace-switcher.png
new file mode 100644
index 000000000..1f651e86c
Binary files /dev/null and b/docs/docs/img/workspace-switcher.png differ
diff --git a/docs/docs/index.mdx b/docs/docs/index.mdx
index b807437eb..eccd877fa 100644
--- a/docs/docs/index.mdx
+++ b/docs/docs/index.mdx
@@ -14,7 +14,7 @@ Wave is an [open-source](https://github.com/wavetermdev/waveterm) terminal that
Wave isn't just another terminal emulator; it's a rethink on how terminals are built. For too long there has been a disconnect between the CLI and the web. If you want fast, keyboard-accessible, easy-to-write applications, you use the CLI, but if you want graphical interfaces, native widgets, copy/paste, scrolling, variable font sizes, then you'd have to turn to the web. Wave's goal is to bridge that gap.
-![Wave Screenshot](/img/wave-screenshot.webp)
+![Wave Screenshot](./img/wave-screenshot.webp)
| Open a new tab |
| | Open a new terminal block (defaults to the same connection and working directory) |
+| | Open a new window |
| | Close the current block |
+| | Close the current tab |
| | Magnify / Un-Magnify the current block |
| | Open the "connection" switcher |
| | Refocus the current block (useful if the block has lost input focus) |
@@ -34,6 +36,7 @@ replace "Cmd" with "Alt" (note that "Ctrl" is "Ctrl" on both Mac, Windows, and L
| | Switch to tab number |
| | Switch tab left |
| | Switch tab right |
+| | Switch to workspace number |
| | Refresh the UI |
## File Preview Keybindings
diff --git a/docs/docs/layout.mdx b/docs/docs/layout.mdx
index 1fe5f5fc7..a7659f59b 100644
--- a/docs/docs/layout.mdx
+++ b/docs/docs/layout.mdx
@@ -1,5 +1,5 @@
---
-sidebar_position: 2
+sidebar_position: 3.5
id: "layout"
title: "Tab Layout System"
---
diff --git a/docs/docs/widgets.mdx b/docs/docs/widgets.mdx
index b54cbbe1c..1b8162d10 100644
--- a/docs/docs/widgets.mdx
+++ b/docs/docs/widgets.mdx
@@ -1,5 +1,5 @@
---
-sidebar_position: 5
+sidebar_position: 3.3
id: "widgets"
title: "Widgets"
---
diff --git a/docs/docs/workspaces.mdx b/docs/docs/workspaces.mdx
new file mode 100644
index 000000000..3b9c279cf
--- /dev/null
+++ b/docs/docs/workspaces.mdx
@@ -0,0 +1,74 @@
+---
+sidebar_position: 3
+id: "workspaces"
+title: "Workspaces"
+---
+
+import WorkspaceSVG from "../../frontend/app/asset/workspace.svg";
+
+# Workspaces
+
+Workspaces are a powerful way to organize your workflows into separate environments, which you can tailor and optimize.
+
+## Workspace Switcher
+
+![Workspace switcher screenshot](./img/workspace-switcher.png#right)
+
+The primary mechanism to interact with workspaces is via the Workspace Switcher, located to the left of the tab bar.
+
+This is where you can create a new workspace, edit how a workspace entry appears, and delete a workspace.
+
+The Workspace Switcher button changes to display the icon and color of the active workspace. If the current workspace is not saved, it will display the icon. Clicking the button will open the Workspace Switcher.
+
+The Switcher contains a list of all saved workspaces for your installation, each with a customizable icon, icon color, and name.
+
+The active workspace for the current window will have a next to it. Any workspace that is currently open in another window will have the icon next to it.
+
+Hovering over a workspace in the switcher will display a icon, which will open an editor pane when clicked, in which you can change the workspace name, icon, and icon color. You can also delete a workspace from this pane.
+
+## Creating a new workspace
+
+Every new window is initialized with a blank workspace containing a single tab with a single terminal block inside it. There are three ways to create a new workspace:
+
+1. Create a new window, either via `File` app menu or using the [keybinding](./keybindings.mdx#global-keybindings). This will create a new window and a new workspace within that.
+2. Create a new workspace via the `Workspace` app menu. This will create a new workspace and switch the current window to that workspace.
+3. If you are on a saved workspace, you can click the "Create new workspace" button at the bottom of the Workspace Switcher. This will create a new workspace and switch the current window to that workspace.
+
+## Saving a workspace
+
+:::note
+
+A new workspace is ephemeral. When a window closes, its workspace, along with all its tabs, is deleted unless the workspace is saved.
+
+The exception to this rule is the last window will be preserved when closed and will be reopened next time you open the app, regardless of whether the workspace is saved.
+
+:::
+
+To preserve a new workspace, you must save it. This can be acheived by clicking the "Save workspace" button at the bottom of the Workspace Switcher.
+
+If you instead see "Create new workspace" at the bottom of the Workspace Switcher, you are already in a saved workspace. You can also confirm this by checking the wording at the top of the Workspace Switcher. For an unsaved workspace, you will see "Open workspace"; for a saved workspace, you will see "Switch workspaces".
+
+Once a workspace is saved, you will see a new entry in the Workspace Switcher list for your saved workspace. It will be named `New Workspace ()`. To make the most of your workspace, is recommended to change this name, and the icon and icon color, to something more memorable or meaningful.
+
+## Switching workspaces
+
+There are two ways to switch workspaces:
+
+1. From an open window, you can open the Workspace Switcher and click on a workspace from the list.
+2. From the Workspace app menu, click on a workspace from the list.
+
+If the workspace is already open in another window (it has the next to it if you are in the Workspace Switcher), that window will take focus.
+
+If the workspace is not open, your current window will switch to it. If your current workspace is unsaved, you will be prompted whether you want to open the new workspace in a new window or whether you want to open it in the current window. **If you choose the latter option, the current workspace and its contents will be deleted.**
+
+The Workspace Switcher button will update with the colored icon for your new active workspace.
+
+## Edit a workspace
+
+:::info
+
+The tabs, layouts, and terminal and AI histories of a [saved workspace](#saving-a-workspace) are persisted automatically, however if you have unsaved file changes in an editor or a webpage, your progress will be lost when you close the window.
+
+:::
+
+To update the name, icon, and icon color of a workspace, hover over the workspace in the Workspace Switcher and click the button that appears. This will open an editor pane, where you can make your changes. They are persisted and updated automatically.
diff --git a/docs/src/css/custom.css b/docs/src/css/custom.css
index 2e98394a2..a874f630f 100644
--- a/docs/src/css/custom.css
+++ b/docs/src/css/custom.css
@@ -66,3 +66,18 @@ body .markdown h2 {
mask: url(/img/discord.svg) no-repeat center / contain;
-webkit-mask: url(/img/discord.svg) no-repeat center / contain;
}
+
+img[src*="#left"] {
+ float: left;
+ margin: 0 10px 10px 0;
+ max-width: 300px;
+}
+img[src*="#right"] {
+ float: right;
+ margin: 0 0 10px 10px;
+ max-width: 300px;
+}
+img[src*="#center"] {
+ display: block;
+ margin: auto;
+}
diff --git a/docs/src/theme/MDXComponents/Heading.tsx b/docs/src/theme/MDXComponents/Heading.tsx
new file mode 100644
index 000000000..0b1cd9f66
--- /dev/null
+++ b/docs/src/theme/MDXComponents/Heading.tsx
@@ -0,0 +1,14 @@
+import type { WrapperProps } from "@docusaurus/types";
+import Heading from "@theme-original/MDXComponents/Heading";
+import type HeadingType from "@theme/MDXComponents/Heading";
+
+type Props = WrapperProps;
+
+export default function HeadingWrapper(props: Props): JSX.Element {
+ return (
+ <>
+
+
+ >
+ );
+}
diff --git a/docs/static/img/workspace.svg b/docs/static/img/workspace.svg
new file mode 100644
index 000000000..220153c89
--- /dev/null
+++ b/docs/static/img/workspace.svg
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/frontend/app/tab/tabbar.tsx b/frontend/app/tab/tabbar.tsx
index d632b0fcb..3c99660e5 100644
--- a/frontend/app/tab/tabbar.tsx
+++ b/frontend/app/tab/tabbar.tsx
@@ -5,7 +5,7 @@ import { Button } from "@/app/element/button";
import { modalsModel } from "@/app/store/modalmodel";
import { WindowDrag } from "@/element/windowdrag";
import { deleteLayoutModelForTab } from "@/layout/index";
-import { atoms, createTab, getApi, globalStore, isDev, PLATFORM, setActiveTab } from "@/store/global";
+import { atoms, createTab, getApi, globalStore, PLATFORM, setActiveTab } from "@/store/global";
import { fireAndForget } from "@/util/util";
import { useAtomValue } from "jotai";
import { OverlayScrollbars } from "overlayscrollbars";
@@ -637,7 +637,7 @@ const TabBar = memo(({ workspace }: TabBarProps) => {
}
const tabsWrapperWidth = tabIds.length * tabWidthRef.current;
- const devLabel = isDev() ? (
+ const devLabel = false ? (