From f1c75dd84a112c2bcafc4b11b4ac6a59729e7f21 Mon Sep 17 00:00:00 2001 From: Ruslan Date: Fri, 14 Aug 2026 07:55:17 +0300 Subject: [PATCH 1/2] feat(editor): add undo/redo buttons to viewer toolbar --- apps/editor/components/viewer-toolbar.tsx | 67 ++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/apps/editor/components/viewer-toolbar.tsx b/apps/editor/components/viewer-toolbar.tsx index a707288ecf..d7822e6c98 100644 --- a/apps/editor/components/viewer-toolbar.tsx +++ b/apps/editor/components/viewer-toolbar.tsx @@ -10,6 +10,10 @@ import { DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, + getHistoryCommandState, + runRedo, + runUndo, + subscribeHistoryCommandState, useEditor, useFloorplanAnnotationVisibility, useFloorplanMode, @@ -37,6 +41,7 @@ import { Layers3, Magnet, PenLine, + Redo2, Ruler, ScanLine, SlidersHorizontal, @@ -44,9 +49,10 @@ import { SquareUserRound, SwatchBook, Tag, + Undo2, } from 'lucide-react' import Image from 'next/image' -import { type ReactNode, useCallback } from 'react' +import { type ReactNode, useCallback, useEffect, useState } from 'react' import { flushSync } from 'react-dom' import { cn } from '@/lib/utils' import { Tooltip, TooltipContent, TooltipTrigger } from './toolbar-tooltip' @@ -686,10 +692,69 @@ function PreviewButton() { ) } +// Undo/Redo toolbar controls. They subscribe to the shared history state +// (`history.ts`) so buttons enable/disable as the scene history grows, and +// route through `runUndo`/`runRedo` so they honor a collaborative host +// delegate when one is installed. Keyboard shortcuts (Ctrl/Cmd+Z and +// Ctrl/Cmd+Shift+Z) are wired separately in `use-keyboard.ts` and land here +// via the same state subscription. +function HistoryControls() { + const [state, setState] = useState(() => getHistoryCommandState()) + + useEffect(() => { + return subscribeHistoryCommandState(() => setState(getHistoryCommandState())) + }, []) + + const undo = () => { + if (!getHistoryCommandState().canUndo) return + runUndo() + } + + const redo = () => { + if (!getHistoryCommandState().canRedo) return + runRedo() + } + + return ( +
+ + + +
+ + + +
+ ) +} + export function CommunityViewerToolbarLeft() { return ( <> + ) From 55a63b694287ce10e8b46f95d5ed000bc821ccb2 Mon Sep 17 00:00:00 2001 From: Ruslan Date: Fri, 14 Aug 2026 08:19:30 +0300 Subject: [PATCH 2/2] docs(changelog): note undo/redo toolbar buttons under Unreleased --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 537d733c01..bfac196ea5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Features + +- Undo/Redo buttons in the viewer toolbar (top-left, alongside the collapse and view-mode controls). The buttons subscribe to the history store via `subscribeHistoryCommandState`, dispatch through `runUndo`/`runRedo` (respecting the collaborative history delegate), and disable when nothing can be undone/redone. Keyboard shortcuts were already wired: Ctrl/Cmd+Z undo, Ctrl/Cmd+Shift+Z redo. + ### Fixes - Preserve custom scene materials across save, load, clone, fork, and live sync. Materials were dropped at every persistence boundary, so a scene reopened with default surfaces. Collections were dropped on MCP import for the same reason ([#597](https://github.com/pascalorg/editor/pull/597)) by [@ShiroKSH](https://github.com/ShiroKSH)