Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/bottom-bar-glass-and-layouts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hashintel/petrinaut": patch
---

Renders the bottom toolbar's glass as a blur on browsers that cannot refract it, and offers two more toolbar layouts in Settings.
6 changes: 6 additions & 0 deletions libs/@hashintel/petrinaut/docs/drawing-a-net.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ viewport controls. Where even that leaves too little room it shrinks to the
cursor, the panel toggle, the diagnostics status and Play; point at it, or tab
into it, and the rest comes back for as long as you stay on it.

The toolbar is drawn as frosted glass over the canvas. Chromium-based browsers
refract the canvas through it, and settle into that refraction over a moment
after the bar appears; Safari and Firefox show a plain blur instead. How its
controls are grouped is a choice: see [Bottom toolbar](visual-settings.md#bottom-toolbar-experimental)
in the settings dialog.

<img width="1793" height="1175" alt="full-editor" src="https://github.com/user-attachments/assets/ea41efe8-9056-479b-a936-e0d5e4196b11" />

## Top bar
Expand Down
12 changes: 11 additions & 1 deletion libs/@hashintel/petrinaut/docs/visual-settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Changes apply immediately and are saved as your preferences across nets. On host

| Section | Settings |
| -------------- | -------------------------------------------------------------------- |
| **General** | Animations, panel loading, and the welcome guide. |
| **General** | Animations, panel loading, the welcome guide, and toolbar layout. |
| **Viewport** | Minimap, compact nodes, arc rendering, grid snapping, and selection. |
| **Simulation** | Experimental compute, parameter sweeps, and optimization options. |
| **Labs** | Experimental modeling views, code layouts, and developer tools. |
Expand All @@ -35,6 +35,16 @@ When enabled, hidden panels remain loaded in the background. Switching between p

Show the getting-started guide the next time you open Petrinaut.

### Bottom toolbar (experimental)

Choose how the toolbar at the bottom of the canvas is laid out. Every layout keeps the same controls and steps aside from the panels in the same way; they differ in how the controls are grouped.

| Layout | Description |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Split** | Two glass segments: the cursor and editing tools on the left, the panel toggle, diagnostics status and playback controls on the right. (Default) |
| **Mode switch** | One segment showing one face at a time. The edit face holds the AI assistant and the tools that add nodes; the simulate face holds diagnostics, Play, the playback speed and the scrubber. The Edit / Simulate switch at the right end flips between them, and starting a run flips to the simulate face by itself. The cursor button is tinted blue on the edit face and purple on the simulate face. |
| **Single** | One segment holding every control in one row: cursor, AI assistant and editing tools, then diagnostics status, a filled blue Play button, the scrubber and the playback settings, with the panel toggle at the far end. |

## Viewport

### Minimap
Expand Down
23 changes: 23 additions & 0 deletions libs/@hashintel/petrinaut/src/react/state/user-settings-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,25 @@ import type {

export type ArcRendering = "smoothstep" | "bezier" | "custom";

/**
* How the bottom toolbar is laid out. `split` keeps the edit tools and the
* playback controls in two glass segments; `modes` is the single segment from
* the design file, which shows either face behind an Edit / Simulate switch;
* `single` is one segment holding every control.
*/
export type BottomBarVariant = "split" | "modes" | "single";

const bottomBarVariants: readonly BottomBarVariant[] = [
"split",
"modes",
"single",
];

/** Whether a persisted value names a layout this build has. */
export const isBottomBarVariant = (value: unknown): value is BottomBarVariant =>
typeof value === "string" &&
(bottomBarVariants as readonly string[]).includes(value);

export type SubViewSectionSettings = {
collapsed: boolean;
/** Last known panel height in pixels */
Expand All @@ -37,6 +56,7 @@ export type UserSettings = {
enableExperimentalIconPack: boolean;
enableAutomaticArcConnections: boolean;
arcRendering: ArcRendering;
bottomBarVariant: BottomBarVariant;
cursorMode: CursorMode;
isLeftSidebarOpen: boolean;
leftSidebarWidth: number;
Expand Down Expand Up @@ -117,6 +137,7 @@ export type UserSettingsActions = {
setEnableExperimentalIconPack: (value: boolean) => void;
setEnableAutomaticArcConnections: (value: boolean) => void;
setArcRendering: (value: ArcRendering) => void;
setBottomBarVariant: (value: BottomBarVariant) => void;
setIsLeftSidebarOpen: (value: boolean) => void;
setLeftSidebarWidth: (value: number) => void;
setPropertiesPanelWidth: (value: number) => void;
Expand Down Expand Up @@ -154,6 +175,7 @@ export const defaultUserSettings: UserSettings = {
enableExperimentalIconPack: false,
enableAutomaticArcConnections: false,
arcRendering: "custom",
bottomBarVariant: "split",
cursorMode: "pan",
isLeftSidebarOpen: true,
leftSidebarWidth: DEFAULT_LEFT_SIDEBAR_WIDTH,
Expand Down Expand Up @@ -190,6 +212,7 @@ export const defaultUserSettingsContextValue: UserSettingsContextValue = {
setEnableExperimentalIconPack: () => {},
setEnableAutomaticArcConnections: () => {},
setArcRendering: () => {},
setBottomBarVariant: () => {},
setIsLeftSidebarOpen: () => {},
setLeftSidebarWidth: () => {},
setPropertiesPanelWidth: () => {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { use, useEffect, useState } from "react";
import {
defaultUserSettings,
defaultUserSettingsContextValue,
isBottomBarVariant,
UserSettingsContext,
} from "./user-settings-context";
import { rememberCanvasViewport } from "./user-settings-provider/remember-canvas-viewport";
Expand All @@ -15,6 +16,7 @@ import type {
} from "./editor-context";
import type {
ArcRendering,
BottomBarVariant,
SubViewSectionSettings,
UserSettings,
} from "./user-settings-context";
Expand Down Expand Up @@ -63,6 +65,10 @@ const loadSettings = (): UserSettings => {
...parsed,
// Someone who had selected the GPU globally keeps it available.
webGpuEnabled: parsed.webGpuEnabled ?? computeBackend === "webgpu",
// A layout this build no longer has falls back to the default one.
bottomBarVariant: isBottomBarVariant(parsed.bottomBarVariant)
? parsed.bottomBarVariant
: defaultUserSettings.bottomBarVariant,
};
}
} catch {
Expand Down Expand Up @@ -104,6 +110,8 @@ const OwnedUserSettingsProvider: React.FC<React.PropsWithChildren> = ({
})),
setArcRendering: (value: ArcRendering) =>
setState((prev) => ({ ...prev, arcRendering: value })),
setBottomBarVariant: (value: BottomBarVariant) =>
setState((prev) => ({ ...prev, bottomBarVariant: value })),
setCursorMode: (value: CursorMode) =>
setState((prev) => ({ ...prev, cursorMode: value })),
setIsLeftSidebarOpen: (value: boolean) =>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { use } from "react";

import { EditorContext } from "../../../../../react/state/editor-context";
import { AiAssistantIcon } from "../../../../components/ai-assistant-icon";
import { ToolbarButton } from "./toolbar-button";

/** Opens and closes the AI assistant panel. */
export const AiAssistantToggle: React.FC = () => {
const { isAiAssistantOpen, toggleAiAssistant } = use(EditorContext);
const label = isAiAssistantOpen ? "Hide AI assistant" : "Show AI assistant";

return (
<ToolbarButton
tooltip={label}
onClick={toggleAiAssistant}
isSelected={isAiAssistantOpen}
ariaLabel={label}
ariaExpanded={isAiAssistantOpen}
>
<AiAssistantIcon size={18} />
</ToolbarButton>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type {
CursorMode,
EditorState,
} from "../../../../../react/state/editor-context";

/** What every layout of the bar is given to render its controls from. */
export interface BarContentProps {
mode: EditorState["globalMode"];
editionMode: EditorState["editionMode"];
onEditionModeChange: (mode: EditorState["editionMode"]) => void;
cursorMode: CursorMode;
onCursorModeChange: (mode: CursorMode) => void;
hasAiAssistant: boolean;
}
Loading
Loading