From d60382bf3d1763a1730fdce9a5c5f1e2e54a4485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Ma=C5=82ecki?= <92953623+p-malecki@users.noreply.github.com> Date: Mon, 2 Dec 2024 12:51:36 +0100 Subject: [PATCH 1/4] Toolbelt WIP --- .../components/shared/ToolbeltButton.css | 104 ++++++++++++++++++ .../components/shared/ToolbeltButton.tsx | 65 +++++++++++ .../src/webview/views/PreviewView.tsx | 7 ++ 3 files changed, 176 insertions(+) create mode 100644 packages/vscode-extension/src/webview/components/shared/ToolbeltButton.css create mode 100644 packages/vscode-extension/src/webview/components/shared/ToolbeltButton.tsx diff --git a/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.css b/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.css new file mode 100644 index 000000000..e1c8b7dc7 --- /dev/null +++ b/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.css @@ -0,0 +1,104 @@ +.toolbelt-button-container { + display: flex; + align-items: center; + max-height: 36px; + height: 36px; +} + +.toolbelt-button-main-button { + cursor: pointer; + height: 80%; + display: flex; + align-items: center; + padding: 5px; + background: none; + border: 0px solid transparent; + border-radius: 10px 0px 0px 10px; +} + +.toolbelt-button-main-button:hover { + background-color: var(--swm-button-hover); +} +.toolbelt-button-main-button:active { + color: var(--swm-button-active); + background-color: var(--swm-button-active-background); + transform: scale(0.9); +} + +.toolbelt-button-select-trigger { + cursor: default; + height: 100%; + background: none; + border: 0px solid transparent; + border-radius: 0px 10px 10px 0px; +} +.toolbelt-button-select-trigger:hover { + background-color: var(--swm-button-hover); +} + +.toolbelt-button-select-trigger[data-state="open"] { + /* border-radius: 0 0 18px 18px; */ +} + +.toolbelt-button-select-trigger[data-disabled] { + background-color: var(--swm-device-select-trigger-disabled); + color: var(--swm-secondary-text); + pointer-events: none; +} + +.toolbelt-button-select-content { + background-color: var(--swm-popover-background); + border-radius: 6px; + padding: 4px; + animation-duration: 400ms; + animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); + will-change: transform, opacity; + box-shadow: var(--swm-backdrop-shadow); + max-height: calc(var(--radix-dropdown-menu-content-available-height) - 40px); + overflow-y: auto; +} + +.toolbelt-button-select-content[data-side="bottom"] { + animation-name: slideUpAndFade; +} + +.toolbelt-button-select-content[data-side="top"] { + animation-name: slideDownAndFade; +} + +.toolbelt-button-select-item { + padding: 10px; + cursor: pointer; +} + +.toolbelt-button-select-item:hover { + background-color: var(--swm-button-hover); +} + +.toolbelt-button-icon { + margin-right: 8px; +} + +@keyframes slideUpAndFade { + from { + opacity: 0; + transform: translateY(3px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slideDownAndFade { + from { + opacity: 0; + transform: translateY(-3px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} diff --git a/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.tsx b/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.tsx new file mode 100644 index 000000000..4b4cabdff --- /dev/null +++ b/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.tsx @@ -0,0 +1,65 @@ +import React, { useState } from "react"; +import * as Select from "@radix-ui/react-select"; +import "./ToolbeltButton.css"; + + +export interface ToolbeltOption { + value: string; + label: string; + icon?: React.ReactNode; +} + +interface ToolbeltButtonProps { + options: ToolbeltOption[], + defaultOptionIndex?: number, + onSelect: (value: string) => void, +} + +function ToolbeltButton({ + options, + defaultOptionIndex = 0, + onSelect, +}: ToolbeltButtonProps) { + + const [selectedOption, setSelectedOption] = useState(options[defaultOptionIndex]); + + const handleSelect = (value: string) => { + const selected = options.find(option => option.value === value); + setSelectedOption(selected || options[defaultOptionIndex]); + onSelect(value); + }; + + return ( +
+ + + + + + + + + + + {options.map((option) => ( + +
+ {option.icon && {option.icon}} + {option.label} +
+
+ ))} +
+
+
+
+
+ ); +} + +export default ToolbeltButton; diff --git a/packages/vscode-extension/src/webview/views/PreviewView.tsx b/packages/vscode-extension/src/webview/views/PreviewView.tsx index dec91306f..e88b0d5f2 100644 --- a/packages/vscode-extension/src/webview/views/PreviewView.tsx +++ b/packages/vscode-extension/src/webview/views/PreviewView.tsx @@ -14,6 +14,7 @@ import { useProject } from "../providers/ProjectProvider"; import DeviceSelect from "../components/DeviceSelect"; import { InspectDataMenu } from "../components/InspectDataMenu"; import Button from "../components/shared/Button"; +import ToolbeltButton, { ToolbeltOption } from "../components/shared/ToolbeltButton"; import { Frame, InspectDataStackItem, @@ -205,11 +206,17 @@ function PreviewView() { .toString() .padStart(2, "0")}`; + + const toolbeltOptions: ToolbeltOption[] = [ + { value: "tool1", label: "tool1", icon: }, + ]; + return (
+ { {}} />} { Date: Mon, 2 Dec 2024 19:42:25 +0100 Subject: [PATCH 2/4] WIP 2 --- .../components/shared/ToolbeltButton.css | 45 +++---------- .../components/shared/ToolbeltButton.tsx | 65 ++++++++----------- .../src/webview/views/PreviewView.tsx | 43 +++++++++++- 3 files changed, 78 insertions(+), 75 deletions(-) diff --git a/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.css b/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.css index e1c8b7dc7..2f5b41ca2 100644 --- a/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.css +++ b/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.css @@ -36,8 +36,15 @@ background-color: var(--swm-button-hover); } -.toolbelt-button-select-trigger[data-state="open"] { - /* border-radius: 0 0 18px 18px; */ +.toolbelt-button-select-trigger-value { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; } .toolbelt-button-select-trigger[data-disabled] { @@ -50,22 +57,12 @@ background-color: var(--swm-popover-background); border-radius: 6px; padding: 4px; - animation-duration: 400ms; - animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); will-change: transform, opacity; box-shadow: var(--swm-backdrop-shadow); max-height: calc(var(--radix-dropdown-menu-content-available-height) - 40px); overflow-y: auto; } -.toolbelt-button-select-content[data-side="bottom"] { - animation-name: slideUpAndFade; -} - -.toolbelt-button-select-content[data-side="top"] { - animation-name: slideDownAndFade; -} - .toolbelt-button-select-item { padding: 10px; cursor: pointer; @@ -78,27 +75,3 @@ .toolbelt-button-icon { margin-right: 8px; } - -@keyframes slideUpAndFade { - from { - opacity: 0; - transform: translateY(3px); - } - - to { - opacity: 1; - transform: translateY(0); - } -} - -@keyframes slideDownAndFade { - from { - opacity: 0; - transform: translateY(-3px); - } - - to { - opacity: 1; - transform: translateY(0); - } -} diff --git a/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.tsx b/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.tsx index 4b4cabdff..b0f225696 100644 --- a/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.tsx +++ b/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.tsx @@ -1,63 +1,54 @@ import React, { useState } from "react"; -import * as Select from "@radix-ui/react-select"; +import * as DropdownMenu from "@radix-ui/react-dropdown-menu"; import "./ToolbeltButton.css"; - export interface ToolbeltOption { - value: string; label: string; + button: React.ReactNode; icon?: React.ReactNode; } interface ToolbeltButtonProps { - options: ToolbeltOption[], - defaultOptionIndex?: number, - onSelect: (value: string) => void, + options: ToolbeltOption[]; + defaultOptionIndex?: number; + disabled?: boolean; } function ToolbeltButton({ options, defaultOptionIndex = 0, - onSelect, + disabled = false, }: ToolbeltButtonProps) { - const [selectedOption, setSelectedOption] = useState(options[defaultOptionIndex]); - const handleSelect = (value: string) => { - const selected = options.find(option => option.value === value); - setSelectedOption(selected || options[defaultOptionIndex]); - onSelect(value); - }; + const handleSelect = (option: ToolbeltOption) => { + setSelectedOption(option); + }; return (
- - - + + - - - - - - {options.map((option) => ( - -
- {option.icon && {option.icon}} - {option.label} -
-
- ))} -
-
-
-
+ + + {options.map((option) => ( + handleSelect(option)} + className="toolbelt-button-dropdown-item"> +
+ {option.icon && {option.icon}} + {option.label} +
+
+ ))} +
+
); } diff --git a/packages/vscode-extension/src/webview/views/PreviewView.tsx b/packages/vscode-extension/src/webview/views/PreviewView.tsx index e88b0d5f2..4cd27be1b 100644 --- a/packages/vscode-extension/src/webview/views/PreviewView.tsx +++ b/packages/vscode-extension/src/webview/views/PreviewView.tsx @@ -208,15 +208,54 @@ function PreviewView() { const toolbeltOptions: ToolbeltOption[] = [ - { value: "tool1", label: "tool1", icon: }, + { + label: "tool1", + button: ( + { + }} + tooltip={{ + label: "Open logs panel", + }} + disabled={devicesNotFound}> + + + ), + icon: , + }, ]; + // const toolbeltOptions: ToolbeltOption[] = [ + // { + // value: "tool1", + // label: "tool1", + // icon: ( + // + // {isRecording ? ( + //
+ //
+ // {recordingTimeFormat} + //
+ // ) : ( + // + // )} + // + // ), + // }, + // ]; + return (
- { {}} />} + {} { Date: Tue, 3 Dec 2024 14:17:32 +0100 Subject: [PATCH 3/4] Finish Toolbelt --- .../components/shared/ToolbeltButton.css | 63 +++++++------ .../components/shared/ToolbeltButton.tsx | 56 ++++++----- .../src/webview/views/PreviewView.tsx | 93 ++++++++++--------- 3 files changed, 113 insertions(+), 99 deletions(-) diff --git a/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.css b/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.css index 2f5b41ca2..1f390c5b4 100644 --- a/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.css +++ b/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.css @@ -7,10 +7,10 @@ .toolbelt-button-main-button { cursor: pointer; - height: 80%; + height: 28px; display: flex; align-items: center; - padding: 5px; + padding: 5px 0px; background: none; border: 0px solid transparent; border-radius: 10px 0px 0px 10px; @@ -25,53 +25,56 @@ transform: scale(0.9); } -.toolbelt-button-select-trigger { +.toolbelt-button-dropdown-trigger { cursor: default; height: 100%; background: none; border: 0px solid transparent; border-radius: 0px 10px 10px 0px; } -.toolbelt-button-select-trigger:hover { +.toolbelt-button-dropdown-trigger:hover { background-color: var(--swm-button-hover); } - -.toolbelt-button-select-trigger-value { - position: absolute; - width: 1px; - height: 1px; - margin: -1px; - padding: 0; - overflow: hidden; - clip: rect(0, 0, 0, 0); - border: 0; -} - -.toolbelt-button-select-trigger[data-disabled] { - background-color: var(--swm-device-select-trigger-disabled); +.toolbelt-button-dropdown-trigger[data-disabled] { color: var(--swm-secondary-text); pointer-events: none; } +.toolbelt-button-dropdown-trigger[data-state="open"] { + background: var(--swm-dropdown-item-highlighted); + border-radius: 0px 10px 0px 0px; +} -.toolbelt-button-select-content { - background-color: var(--swm-popover-background); - border-radius: 6px; - padding: 4px; - will-change: transform, opacity; +.toolbelt-button-dropdown-content { + background: var(--swm-popover-background); + border-radius: 7px 0px 7px 7px; + padding: 5px; box-shadow: var(--swm-backdrop-shadow); max-height: calc(var(--radix-dropdown-menu-content-available-height) - 40px); + min-width: 150px; overflow-y: auto; } -.toolbelt-button-select-item { - padding: 10px; - cursor: pointer; +.toolbelt-button-dropdown-item-wraper { + display: flex; + width: 100%; + align-items: center; + gap: 8px; } -.toolbelt-button-select-item:hover { - background-color: var(--swm-button-hover); +.toolbelt-button-dropdown-item-wraper:hover { + background-color: var(--swm-dropdown-item-highlighted); + outline: none; } -.toolbelt-button-icon { - margin-right: 8px; +.toolbelt-button-dropdown-item-content { + color: var(--swm-default-text); + font-size: 13px; + line-height: 1; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + height: 28px; + width: 100%; + gap: 5px; } diff --git a/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.tsx b/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.tsx index b0f225696..e80a8dcd9 100644 --- a/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.tsx +++ b/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.tsx @@ -4,8 +4,9 @@ import "./ToolbeltButton.css"; export interface ToolbeltOption { label: string; - button: React.ReactNode; - icon?: React.ReactNode; + component: React.ReactElement; + dropdownIcon: React.ReactNode; + keybinding?: React.ReactNode; } interface ToolbeltButtonProps { @@ -19,35 +20,44 @@ function ToolbeltButton({ defaultOptionIndex = 0, disabled = false, }: ToolbeltButtonProps) { - const [selectedOption, setSelectedOption] = useState(options[defaultOptionIndex]); + const [selectedOptionIndex, setSelectedOptionIndex] = useState(defaultOptionIndex); - const handleSelect = (option: ToolbeltOption) => { - setSelectedOption(option); - }; + const handleSelect = (option: ToolbeltOption) => { + const index = options.findIndex((o) => o.label === option.label); + setSelectedOptionIndex(index); + }; return (
- + {React.cloneElement(options[selectedOptionIndex].component, { + className: `toolbelt-button-main-button ${options[selectedOptionIndex].component.props.className}`, + })} - + - - {options.map((option) => ( - handleSelect(option)} - className="toolbelt-button-dropdown-item"> -
- {option.icon && {option.icon}} - {option.label} -
-
- ))} -
+ + + {options.map((option) => ( + handleSelect(option)} + className="toolbelt-button-select-item"> + + {option.dropdownIcon && {option.dropdownIcon}} +
+ {option.label} + {options[selectedOptionIndex].keybinding} +
+
+
+ ))} +
+
); diff --git a/packages/vscode-extension/src/webview/views/PreviewView.tsx b/packages/vscode-extension/src/webview/views/PreviewView.tsx index 4cd27be1b..e42d7a361 100644 --- a/packages/vscode-extension/src/webview/views/PreviewView.tsx +++ b/packages/vscode-extension/src/webview/views/PreviewView.tsx @@ -14,7 +14,7 @@ import { useProject } from "../providers/ProjectProvider"; import DeviceSelect from "../components/DeviceSelect"; import { InspectDataMenu } from "../components/InspectDataMenu"; import Button from "../components/shared/Button"; -import ToolbeltButton, { ToolbeltOption } from "../components/shared/ToolbeltButton"; +import ToolbeltButton from "../components/shared/ToolbeltButton"; import { Frame, InspectDataStackItem, @@ -29,6 +29,7 @@ import "./PreviewView.css"; import ReplayIcon from "../components/icons/ReplayIcon"; import RecordingIcon from "../components/icons/RecordingIcon"; import { ActivateLicenseView } from "./ActivateLicenseView"; +import { KeybindingInfo } from "../components/shared/KeybindingInfo"; const MAX_RECORDING_TIME_SEC = 10 * 60; @@ -206,56 +207,56 @@ function PreviewView() { .toString() .padStart(2, "0")}`; - - const toolbeltOptions: ToolbeltOption[] = [ - { - label: "tool1", - button: ( - { - }} - tooltip={{ - label: "Open logs panel", - }} - disabled={devicesNotFound}> - - - ), - icon: , - }, - ]; - - // const toolbeltOptions: ToolbeltOption[] = [ - // { - // value: "tool1", - // label: "tool1", - // icon: ( - // - // {isRecording ? ( - //
- //
- // {recordingTimeFormat} - //
- // ) : ( - // - // )} - // - // ), - // }, - // ]; - return (
- {} + { + + {isRecording ? ( +
+
+ {recordingTimeFormat} +
+ ) : ( + + )} + + ), + dropdownIcon: , + keybinding: , + }, + { + label: "Screenshot", + component: ( + { + console.log("FRYTKI screenshot"); + }}> + + + ), + dropdownIcon: , + keybinding: , + }, + ]} + disabled={devicesNotFound || isStarting} + /> + } { Date: Tue, 3 Dec 2024 14:28:27 +0100 Subject: [PATCH 4/4] Move example to ToolbeltButton --- .../components/shared/ToolbeltButton.tsx | 47 +++++++++++++++++++ .../src/webview/views/PreviewView.tsx | 47 ------------------- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.tsx b/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.tsx index e80a8dcd9..a0e97d45f 100644 --- a/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.tsx +++ b/packages/vscode-extension/src/webview/components/shared/ToolbeltButton.tsx @@ -64,3 +64,50 @@ function ToolbeltButton({ } export default ToolbeltButton; + +// EXAMPLE USAGE (WITH RECORDING AND SCREENSHOTS TOOLS): +/* + { + + {isRecording ? ( +
+
+ {recordingTimeFormat} +
+ ) : ( + + )} + + ), + dropdownIcon: , + keybinding: , // TODO add shortcuts + }, + { + label: "Screenshot", + component: ( + {}}> + + + ), + dropdownIcon: , + keybinding: , // TODO add shortcuts + }, + ]} + disabled={devicesNotFound || isStarting} + />; + } + */ diff --git a/packages/vscode-extension/src/webview/views/PreviewView.tsx b/packages/vscode-extension/src/webview/views/PreviewView.tsx index e42d7a361..dec91306f 100644 --- a/packages/vscode-extension/src/webview/views/PreviewView.tsx +++ b/packages/vscode-extension/src/webview/views/PreviewView.tsx @@ -14,7 +14,6 @@ import { useProject } from "../providers/ProjectProvider"; import DeviceSelect from "../components/DeviceSelect"; import { InspectDataMenu } from "../components/InspectDataMenu"; import Button from "../components/shared/Button"; -import ToolbeltButton from "../components/shared/ToolbeltButton"; import { Frame, InspectDataStackItem, @@ -29,7 +28,6 @@ import "./PreviewView.css"; import ReplayIcon from "../components/icons/ReplayIcon"; import RecordingIcon from "../components/icons/RecordingIcon"; import { ActivateLicenseView } from "./ActivateLicenseView"; -import { KeybindingInfo } from "../components/shared/KeybindingInfo"; const MAX_RECORDING_TIME_SEC = 10 * 60; @@ -212,51 +210,6 @@ function PreviewView() {
- { - - {isRecording ? ( -
-
- {recordingTimeFormat} -
- ) : ( - - )} - - ), - dropdownIcon: , - keybinding: , - }, - { - label: "Screenshot", - component: ( - { - console.log("FRYTKI screenshot"); - }}> - - - ), - dropdownIcon: , - keybinding: , - }, - ]} - disabled={devicesNotFound || isStarting} - /> - } {