diff --git a/webview-ui/src/components/common/CheckmarkControl.tsx b/webview-ui/src/components/common/CheckmarkControl.tsx index 551406c3f6..26d22da3c4 100644 --- a/webview-ui/src/components/common/CheckmarkControl.tsx +++ b/webview-ui/src/components/common/CheckmarkControl.tsx @@ -2,7 +2,6 @@ import { flip, offset, shift, useFloating } from "@floating-ui/react" import { CheckpointRestoreRequest } from "@shared/proto/cline/checkpoints" import { Int64Request } from "@shared/proto/cline/common" import { ClineCheckpointRestore } from "@shared/WebviewMessage" -import { VSCodeButton } from "@vscode/webview-ui-toolkit/react" import { useCallback, useEffect, useRef, useState } from "react" import { createPortal } from "react-dom" import styled from "styled-components" @@ -21,6 +20,7 @@ export const CheckmarkControl = ({ messageTs, isCheckpointCheckedOut }: Checkmar const [restoreWorkspaceDisabled, setRestoreWorkspaceDisabled] = useState(false) const [restoreBothDisabled, setRestoreBothDisabled] = useState(false) const [showRestoreConfirm, setShowRestoreConfirm] = useState(false) + const [showMoreOptions, setShowMoreOptions] = useState(false) const { onRelinquishControl } = useExtensionState() // Debounce @@ -92,6 +92,7 @@ export const CheckmarkControl = ({ messageTs, isCheckpointCheckedOut }: Checkmar setRestoreWorkspaceDisabled(false) setRestoreBothDisabled(false) setShowRestoreConfirm(false) + setShowMoreOptions(false) }) }, [onRelinquishControl]) @@ -216,52 +217,65 @@ export const CheckmarkControl = ({ messageTs, isCheckpointCheckedOut }: Checkmar onMouseLeave={handleMouseLeave} ref={refs.setFloating} style={floatingStyles}> - - - Restore Files - -

- Restores your project's files back to a snapshot taken at this point (use "Compare" to - see what will be reverted) -

-
- - - Restore Task Only - -

Deletes messages after this point (does not affect workspace files)

-
- - + + Restore Files & Task - -

Restores your project's files and deletes all messages after this point

-
+ +

Revert files and clear messages after this point

+ + + setShowMoreOptions(!showMoreOptions)}> + More options + + + + {showMoreOptions && ( + + + + + Restore Files Only + +

Revert files to this checkpoint

+
+ + + + Restore Task Only + +

Clear messages after this point

+
+
+ )} , document.body, )} @@ -394,22 +408,115 @@ const CustomButton = styled.button<{ disabled?: boolean; isActive?: boolean; $is } ` -const RestoreOption = styled.div` - &:not(:last-child) { - margin-bottom: 10px; - padding-bottom: 4px; - border-bottom: 1px solid var(--vscode-editorGroup-border); - } +const PrimaryRestoreOption = styled.div` + margin-bottom: 12px; p { - margin: 0 0 2px 0; + margin: 8px 0 0 0; color: var(--vscode-descriptionForeground); font-size: 11px; line-height: 14px; } +` - &:last-child p { - margin: 0 0 -2px 0; +const PrimaryButton = styled.button` + width: 100%; + padding: 6px 10px; + background: var(--vscode-button-background); + color: var(--vscode-button-foreground); + border: none; + border-radius: 3px; + font-size: 13px; + font-weight: 500; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: background 0.1s ease; + margin-bottom: 8px; + + &:hover:not(:disabled) { + background: var(--vscode-button-hoverBackground); + } + + &:disabled { + opacity: 0.5; + cursor: not-allowed; + } +` + +const MoreOptionsToggle = styled.button` + width: 100%; + padding: 2px 0; + background: transparent; + color: var(--vscode-textLink-foreground); + border: none; + font-size: 11px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: flex-start; + transition: opacity 0.1s ease; + opacity: 0.8; + margin-bottom: -4px; + &:hover { + opacity: 1; + } +` + +const AdditionalOptions = styled.div` + padding-top: 8px; + margin-top: 6px; + border-top: 1px solid var(--vscode-editorGroup-border); + animation: slideDown 0.15s ease-out; + + @keyframes slideDown { + from { + opacity: 0; + transform: translateY(-4px); + } + to { + opacity: 1; + transform: translateY(0); + } + } +` + +const RestoreOption = styled.div` + &:not(:last-child) { + margin-bottom: 12px; + } + + p { + margin: 8px 0 0 0; + color: var(--vscode-descriptionForeground); + font-size: 11px; + line-height: 14px; + } +` + +const SecondaryButton = styled.button` + width: 100%; + padding: 5px 8px; + background: var(--vscode-button-secondaryBackground); + color: var(--vscode-button-secondaryForeground); + border: 1px solid var(--vscode-editorGroup-border); + border-radius: 3px; + font-size: 12px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.1s ease; + margin-bottom: 8px; + + &:hover:not(:disabled) { + background: var(--vscode-button-secondaryHoverBackground); + } + + &:disabled { + opacity: 0.5; + cursor: not-allowed; } ` @@ -417,10 +524,11 @@ const RestoreConfirmTooltip = styled.div` position: fixed; background: ${CODE_BLOCK_BG_COLOR}; border: 1px solid var(--vscode-editorGroup-border); - padding: 12px; - border-radius: 3px; - width: min(calc(100vw - 54px), 600px); + padding: 14px; + border-radius: 5px; + width: min(calc(100vw - 54px), 200px); z-index: 1000; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); // Add invisible padding to create a safe hover zone &::before { @@ -463,9 +571,10 @@ const RestoreConfirmTooltip = styled.div` } p { - margin: 0 0 6px 0; + margin: 0; color: var(--vscode-descriptionForeground); - font-size: 12px; + font-size: 11px; + line-height: 14px; white-space: normal; word-wrap: break-word; }