Add a component for toolbar buttons with a dropdown, consolidate Constrain actions under one (#2327)

This commit is contained in:
Frank Noirot
2024-05-10 19:02:11 -04:00
committed by GitHub
parent d0f9ae475f
commit 726fd02bad
36 changed files with 238 additions and 121 deletions

View File

@ -131,6 +131,7 @@ test('Basic sketch', async ({ page }) => {
// selected two lines therefore there should be two cursors
await expect(page.locator('.cm-cursor')).toHaveCount(2)
await page.getByRole('button', { name: 'Constrain' }).click()
await page.getByRole('button', { name: 'Equal Length' }).click()
await expect(page.locator('.cm-content'))
@ -937,11 +938,14 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
// click a segment hold shift and click an axis, see that a relevant constraint is enabled
await topHorzSegmentClick()
await page.keyboard.down('Shift')
const constrainButton = page.getByRole('button', { name: 'Constrain' })
const absYButton = page.getByRole('button', { name: 'ABS Y' })
await constrainButton.click()
await expect(absYButton).toBeDisabled()
await page.waitForTimeout(100)
await xAxisClick()
await page.keyboard.up('Shift')
await constrainButton.click()
await absYButton.and(page.locator(':not([disabled])')).waitFor()
await expect(absYButton).not.toBeDisabled()
@ -951,12 +955,14 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
await page.waitForTimeout(100)
// same selection but click the axis first
await xAxisClick()
await constrainButton.click()
await expect(absYButton).toBeDisabled()
await page.keyboard.down('Shift')
await page.waitForTimeout(100)
await topHorzSegmentClick()
await page.keyboard.up('Shift')
await constrainButton.click()
await expect(absYButton).not.toBeDisabled()
// clear selection by clicking on nothing
@ -965,10 +971,12 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
// check the same selection again by putting cursor in code first then selecting axis
await page.getByText(` |> line([-${commonPoints.num2}, 0], %)`).click()
await page.keyboard.down('Shift')
await constrainButton.click()
await expect(absYButton).toBeDisabled()
await page.waitForTimeout(100)
await xAxisClick()
await page.keyboard.up('Shift')
await constrainButton.click()
await expect(absYButton).not.toBeDisabled()
// clear selection by clicking on nothing
@ -1902,6 +1910,7 @@ test('Can code mod a line length', async ({ page }) => {
const startXPx = 500
await page.mouse.move(startXPx + PUR * 15, 250 - PUR * 10)
await page.mouse.click(615, 102)
await page.getByRole('button', { name: 'Constrain', exact: true }).click()
await page.getByRole('button', { name: 'length', exact: true }).click()
await page.getByText('Add constraining value').click()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

@ -11,17 +11,18 @@ import {
useNetworkStatus,
} from 'components/NetworkHealthIndicator'
import { useStore } from 'useStore'
import { ActionButtonDropdown } from 'components/ActionButtonDropdown'
export const Toolbar = () => {
const { commandBarSend } = useCommandsContext()
const { state, send, context } = useModelingContext()
const toolbarButtonsRef = useRef<HTMLUListElement>(null)
const iconClassName =
'group-disabled:text-chalkboard-50 group-enabled:group-hover:!text-chalkboard-10 group-pressed:!text-chalkboard-10'
'group-disabled:text-chalkboard-50 group-enabled:group-hover:!text-primary dark:group-enabled:group-hover:!text-inherit group-pressed:!text-chalkboard-10 group-ui-open:!text-chalkboard-10 dark:group-ui-open:!text-chalkboard-10'
const bgClassName =
'group-disabled:!bg-transparent group-enabled:group-hover:bg-primary group-pressed:bg-primary'
'group-disabled:!bg-transparent group-enabled:group-hover:bg-primary/10 dark:group-enabled:group-hover:bg-primary group-pressed:bg-primary group-ui-open:bg-primary'
const buttonClassName =
'bg-chalkboard-10 dark:bg-chalkboard-100 hover:bg-chalkboard-10 dark:hover:bg-chalkboard-100'
'bg-chalkboard-10 dark:bg-chalkboard-100 enabled:hover:bg-chalkboard-10 dark:enabled:hover:bg-chalkboard-100 pressed:!border-primary ui-open:!border-primary'
const pathId = useMemo(() => {
if (!isSingleCursorInPipe(context.selectionRanges, kclManager.ast)) {
return false
@ -57,10 +58,7 @@ export const Toolbar = () => {
{...props}
ref={toolbarButtonsRef}
onWheel={handleToolbarButtonsWheelEvent}
className={
'm-0 py-1 rounded-l-sm flex gap-2 items-center overflow-x-auto ' +
className
}
className={'m-0 py-1 rounded-l-sm flex gap-2 items-center ' + className}
style={{ scrollbarWidth: 'thin' }}
>
{state.nextEvents.includes('Enter sketch') && (
@ -71,7 +69,7 @@ export const Toolbar = () => {
onClick={() =>
send({ type: 'Enter sketch', data: { forceNewSketch: true } })
}
icon={{
iconStart={{
icon: 'sketch',
iconClassName,
bgClassName,
@ -88,7 +86,7 @@ export const Toolbar = () => {
className={buttonClassName}
Element="button"
onClick={() => send({ type: 'Enter sketch' })}
icon={{
iconStart={{
icon: 'sketch',
iconClassName,
bgClassName,
@ -105,7 +103,7 @@ export const Toolbar = () => {
className={buttonClassName}
Element="button"
onClick={() => send({ type: 'Cancel' })}
icon={{
iconStart={{
icon: 'arrowLeft',
iconClassName,
bgClassName,
@ -128,7 +126,7 @@ export const Toolbar = () => {
: send('Equip Line tool')
}
aria-pressed={state?.matches('Sketch.Line tool')}
icon={{
iconStart={{
icon: 'line',
iconClassName,
bgClassName,
@ -148,7 +146,7 @@ export const Toolbar = () => {
: send('Equip tangential arc to')
}
aria-pressed={state.matches('Sketch.Tangential arc to')}
icon={{
iconStart={{
icon: 'arc',
iconClassName,
bgClassName,
@ -172,7 +170,7 @@ export const Toolbar = () => {
: send('Equip rectangle tool')
}
aria-pressed={state.matches('Sketch.Rectangle tool')}
icon={{
iconStart={{
icon: 'rectangle',
iconClassName,
bgClassName,
@ -194,7 +192,13 @@ export const Toolbar = () => {
</>
)}
{state.matches('Sketch.SketchIdle') &&
state.nextEvents
state.nextEvents.filter(
(eventName) =>
eventName.includes('Make segment') ||
eventName.includes('Constrain')
).length > 0 && (
<ActionButtonDropdown
splitMenuItems={state.nextEvents
.filter(
(eventName) =>
eventName.includes('Make segment') ||
@ -215,31 +219,27 @@ export const Toolbar = () => {
}
return 0
})
.map((eventName) => (
<li className="contents" key={eventName}>
<ActionButton
className={buttonClassName}
Element="button"
key={eventName}
onClick={() => send(eventName)}
disabled={
.map((eventName) => ({
label: eventName
.replace('Make segment ', '')
.replace('Constrain ', ''),
onClick: () => send(eventName),
disabled:
!state.nextEvents
.filter((event) => state.can(event as any))
.includes(eventName) || disableAllButtons
}
title={eventName}
icon={{
icon: 'line',
.includes(eventName) || disableAllButtons,
}))}
className={buttonClassName}
Element="button"
iconStart={{
icon: 'dimension',
iconClassName,
bgClassName,
}}
>
{eventName
.replace('Make segment ', '')
.replace('Constrain ', '')}
</ActionButton>
</li>
))}
Constrain
</ActionButtonDropdown>
)}
{state.matches('idle') && (
<li className="contents">
<ActionButton
@ -257,7 +257,7 @@ export const Toolbar = () => {
? 'extrude'
: 'sketches need to be closed, or not already extruded'
}
icon={{
iconStart={{
icon: 'extrude',
iconClassName,
bgClassName,
@ -272,7 +272,7 @@ export const Toolbar = () => {
}
return (
<menu className="max-w-full overflow-hidden whitespace-nowrap rounded px-1.5 py-0.5 backdrop-blur-sm bg-chalkboard-10/80 dark:bg-chalkboard-110/70 relative">
<menu className="max-w-full whitespace-nowrap rounded px-1.5 py-0.5 backdrop-blur-sm bg-chalkboard-10/80 dark:bg-chalkboard-110/70 relative">
<ToolbarButtons />
</menu>
)

View File

@ -1,11 +1,12 @@
import { ActionIcon, ActionIconProps } from './ActionIcon'
import React from 'react'
import React, { ForwardedRef, forwardRef } from 'react'
import { paths } from 'lib/paths'
import { Link } from 'react-router-dom'
import type { LinkProps } from 'react-router-dom'
interface BaseActionButtonProps {
icon?: ActionIconProps
iconStart?: ActionIconProps
iconEnd?: ActionIconProps
className?: string
}
@ -32,15 +33,15 @@ type ActionButtonAsElement = BaseActionButtonProps &
Element: React.ComponentType<React.HTMLAttributes<HTMLButtonElement>>
}
type ActionButtonProps =
export type ActionButtonProps =
| ActionButtonAsButton
| ActionButtonAsLink
| ActionButtonAsExternal
| ActionButtonAsElement
export const ActionButton = (props: ActionButtonProps) => {
const classNames = `action-button m-0 group mono text-sm flex items-center gap-2 rounded-sm border-solid border border-chalkboard-30 hover:border-chalkboard-40 dark:border-chalkboard-70 dark:hover:border-chalkboard-60 dark:bg-chalkboard-90/50 p-[3px] text-chalkboard-100 dark:text-chalkboard-10 ${
props.icon ? 'pr-2' : 'px-2'
export const ActionButton = forwardRef((props: ActionButtonProps, ref) => {
const classNames = `action-button p-0 m-0 group mono text-xs leading-none flex items-center gap-2 rounded-sm border-solid border border-chalkboard-30 hover:border-chalkboard-40 enabled:dark:border-chalkboard-70 dark:hover:border-chalkboard-60 dark:bg-chalkboard-90/50 text-chalkboard-100 dark:text-chalkboard-10 ${
props.iconStart ? (props.iconEnd ? 'px-0' : 'pr-2') : 'px-2'
} ${props.className ? props.className : ''}`
switch (props.Element) {
@ -48,11 +49,23 @@ export const ActionButton = (props: ActionButtonProps) => {
// Note we have to destructure 'className' and 'Element' out of props
// because we don't want to pass them to the button element;
// the same is true for the other cases below.
const { Element, icon, children, className: _className, ...rest } = props
const {
Element,
iconStart,
iconEnd,
children,
className: _className,
...rest
} = props
return (
<button className={classNames} {...rest}>
{props.icon && <ActionIcon {...icon} />}
<button
ref={ref as ForwardedRef<HTMLButtonElement>}
className={classNames}
{...rest}
>
{iconStart && <ActionIcon {...iconStart} />}
{children}
{iconEnd && <ActionIcon {...iconEnd} />}
</button>
)
}
@ -60,15 +73,22 @@ export const ActionButton = (props: ActionButtonProps) => {
const {
Element,
to,
icon,
iconStart,
iconEnd,
children,
className: _className,
...rest
} = props
return (
<Link to={to || paths.INDEX} className={classNames} {...rest}>
{icon && <ActionIcon {...icon} />}
<Link
ref={ref as ForwardedRef<HTMLAnchorElement>}
to={to || paths.INDEX}
className={classNames}
{...rest}
>
{iconStart && <ActionIcon {...iconStart} />}
{children}
{iconEnd && <ActionIcon {...iconEnd} />}
</Link>
)
}
@ -76,33 +96,42 @@ export const ActionButton = (props: ActionButtonProps) => {
const {
Element,
to,
icon,
iconStart,
iconEnd,
children,
className: _className,
...rest
} = props
return (
<Link
ref={ref as ForwardedRef<HTMLAnchorElement>}
to={to || paths.INDEX}
className={classNames}
{...rest}
target="_blank"
>
{icon && <ActionIcon {...icon} />}
{iconStart && <ActionIcon {...iconStart} />}
{children}
{iconEnd && <ActionIcon {...iconEnd} />}
</Link>
)
}
default: {
const { Element, icon, children, className: _className, ...rest } = props
if (!Element) throw new Error('Element is required')
const {
Element,
iconStart,
children,
className: _className,
...rest
} = props
return (
<Element className={classNames} {...rest}>
{props.icon && <ActionIcon {...props.icon} />}
{props.iconStart && <ActionIcon {...props.iconStart} />}
{children}
{props.iconEnd && <ActionIcon {...props.iconEnd} />}
</Element>
)
}
}
}
})

View File

@ -0,0 +1,55 @@
import { Popover } from '@headlessui/react'
import { ActionButton, ActionButtonProps } from './ActionButton'
type ActionButtonSplitProps = Omit<ActionButtonProps, 'iconEnd'> & {
splitMenuItems: {
label: string
shortcut?: string
onClick: () => void
disabled?: boolean
}[]
}
export function ActionButtonDropdown({
splitMenuItems,
className,
...props
}: ActionButtonSplitProps) {
return (
<Popover className="relative">
<Popover.Button
as={ActionButton}
className={className}
{...props}
Element="button"
iconEnd={{
icon: 'caretDown',
className: 'ui-open:rotate-180',
bgClassName:
'bg-chalkboard-20 dark:bg-chalkboard-80 ui-open:bg-primary ui-open:text-chalkboard-10',
}}
/>
<Popover.Panel
as="ul"
className="absolute z-20 left-1/2 -translate-x-1/2 top-full mt-1 w-fit max-h-[80vh] overflow-y-auto py-2 flex flex-col gap-1 align-stretch text-inherit dark:text-chalkboard-10 bg-chalkboard-10 dark:bg-chalkboard-100 rounded shadow-lg border border-solid border-chalkboard-30 dark:border-chalkboard-80 text-sm m-0 p-0"
>
{splitMenuItems.map((item) => (
<li className="contents" key={item.label}>
<button
onClick={item.onClick}
className="block px-3 py-1 hover:bg-primary/10 dark:hover:bg-chalkboard-80 border-0 m-0 text-sm w-full rounded-none text-left disabled:!bg-transparent dark:disabled:text-chalkboard-60"
disabled={item.disabled}
>
<span className="capitalize">{item.label}</span>
{item.shortcut && (
<kbd className="bg-primary/10 dark:bg-chalkboard-80 dark:group-hover:bg-primary font-mono rounded-sm dark:text-inherit inline-block px-1 border-primary dark:border-chalkboard-90">
{item.shortcut}
</kbd>
)}
</button>
</li>
))}
</Popover.Panel>
</Popover>
)
}

View File

@ -29,10 +29,8 @@ export const ActionIcon = ({
size = 'md',
children,
}: ActionIconProps) => {
// By default, we reverse the icon color and background color in dark mode
const computedIconClassName = `h-auto text-primary dark:text-current !group-disabled:text-chalkboard-60 !group-disabled:text-chalkboard-60 ${iconClassName}`
const computedBgClassName = `bg-primary/10 dark:bg-chalkboard-90 !group-disabled:bg-chalkboard-30 !dark:group-disabled:bg-chalkboard-80 ${bgClassName}`
const computedIconClassName = `h-auto text-inherit dark:text-current !group-disabled:text-chalkboard-60 !group-disabled:text-chalkboard-60 ${iconClassName}`
const computedBgClassName = `bg-chalkboard-20 dark:bg-chalkboard-80 !group-disabled:bg-chalkboard-30 !dark:group-disabled:bg-chalkboard-80 ${bgClassName}`
return (
<div

View File

@ -175,7 +175,7 @@ function ReviewingButton() {
type="submit"
form="review-form"
className="w-fit !p-0 rounded-sm border !border-primary hover:shadow"
icon={{
iconStart={{
icon: 'checkmark',
bgClassName: 'p-1 rounded-sm !bg-primary hover:brightness-110',
iconClassName: '!text-chalkboard-10',
@ -193,7 +193,7 @@ function GatheringArgsButton() {
type="submit"
form="arg-form"
className="w-fit !p-0 rounded-sm border !border-primary hover:shadow"
icon={{
iconStart={{
icon: 'arrowRight',
bgClassName: 'p-1 rounded-sm !bg-primary hover:brightness-110',
iconClassName: '!text-chalkboard-10',

View File

@ -71,6 +71,16 @@ const CustomIconMap = {
/>
</svg>
),
caretDown: (
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M10 11.2929L6.35346 7.64642L5.64636 8.35354L9.64648 12.3536L10.3536 12.3536L14.3535 8.35353L13.6464 7.64643L10 11.2929Z"
fill="currentColor"
/>
</svg>
),
clipboardCheckmark: (
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
@ -101,6 +111,16 @@ const CustomIconMap = {
/>
</svg>
),
dimension: (
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M15.6455 3.6455L14 2V5.291L5.291 14H2L6 18V14.7052L14.7052 6H18L16.3526 4.35261L16.3546 4.35065L15.6475 3.64354L15.6455 3.6455Z"
fill="currentColor"
/>
</svg>
),
equal: (
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path

View File

@ -25,7 +25,7 @@ const DownloadAppBanner = () => {
<ActionButton
Element="button"
onClick={() => setIsBannerDismissed(true)}
icon={{
iconStart={{
icon: 'close',
className: 'p-1',
bgClassName:

View File

@ -29,7 +29,7 @@ export const ErrorPage = () => {
<ActionButton
Element="link"
to={'/'}
icon={{ icon: faHome }}
iconStart={{ icon: faHome }}
data-testid="unexpected-error-home"
>
Go Home
@ -37,14 +37,14 @@ export const ErrorPage = () => {
)}
<ActionButton
Element="button"
icon={{ icon: faRefresh }}
iconStart={{ icon: faRefresh }}
onClick={() => window.location.reload()}
>
Reload
</ActionButton>
<ActionButton
Element="button"
icon={{ icon: faTrash }}
iconStart={{ icon: faTrash }}
onClick={() => {
window.localStorage.clear()
}}
@ -53,7 +53,7 @@ export const ErrorPage = () => {
</ActionButton>
<ActionButton
Element="externalLink"
icon={{ icon: faBug }}
iconStart={{ icon: faBug }}
to="https://github.com/KittyCAD/modeling-app/issues/new"
>
Report Bug

View File

@ -109,7 +109,7 @@ function DeleteConfirmationDialog({
send({ type: 'Delete file', data: fileOrDir })
setIsOpen(false)
}}
icon={{
iconStart={{
icon: faTrashAlt,
bgClassName: 'bg-destroy-80',
iconClassName:
@ -340,7 +340,7 @@ export const FileTreeMenu = () => {
<>
<ActionButton
Element="button"
icon={{
iconStart={{
icon: 'filePlus',
iconClassName: '!text-current',
bgClassName: 'bg-transparent',
@ -355,7 +355,7 @@ export const FileTreeMenu = () => {
<ActionButton
Element="button"
icon={{
iconStart={{
icon: 'folderPlus',
iconClassName: '!text-current',
bgClassName: 'bg-transparent',

View File

@ -85,7 +85,7 @@ function ProjectCard({
<ActionButton
Element="button"
type="submit"
icon={{
iconStart={{
icon: faCheck,
size: 'sm',
className: 'p-1',
@ -99,7 +99,7 @@ function ProjectCard({
</ActionButton>
<ActionButton
Element="button"
icon={{
iconStart={{
icon: faX,
size: 'sm',
iconClassName: 'dark:!text-chalkboard-20',
@ -141,7 +141,7 @@ function ProjectCard({
<div className="absolute z-10 bottom-2 right-2 flex gap-1 items-center opacity-0 group-hover:opacity-100 group-focus-within:opacity-100">
<ActionButton
Element="button"
icon={{
iconStart={{
icon: faPenAlt,
className: 'p-1',
iconClassName: 'dark:!text-chalkboard-20',
@ -161,7 +161,7 @@ function ProjectCard({
</ActionButton>
<ActionButton
Element="button"
icon={{
iconStart={{
icon: faTrashAlt,
className: 'p-1',
size: 'xs',
@ -207,7 +207,7 @@ function ProjectCard({
await handleDeleteProject(project)
setIsConfirmingDelete(false)
}}
icon={{
iconStart={{
icon: faTrashAlt,
bgClassName: 'bg-destroy-80',
className: 'p-1',

View File

@ -165,7 +165,7 @@ function ProjectMenuPopover({
<div className="flex flex-col gap-2 p-4 dark:bg-chalkboard-90">
<ActionButton
Element="button"
icon={{ icon: 'exportFile', className: 'p-1' }}
iconStart={{ icon: 'exportFile', className: 'p-1' }}
className="border-transparent dark:border-transparent"
disabled={!findCommand(exportCommandInfo)}
onClick={() =>
@ -185,7 +185,7 @@ function ProjectMenuPopover({
// Clear the scene and end the session.
engineCommandManager.endSession()
}}
icon={{
iconStart={{
icon: 'arrowLeft',
className: 'p-1',
}}

View File

@ -78,7 +78,7 @@ export const SetVarNameModal = ({
Element="button"
type="submit"
disabled={!isNewVariableNameUnique}
icon={{ icon: faPlus }}
iconStart={{ icon: faPlus }}
>
Add variable
</ActionButton>

View File

@ -59,7 +59,7 @@ export const UpdaterModal = ({
<ActionButton
Element="button"
onClick={() => onResolve({ wantUpdate: false })}
icon={{
iconStart={{
icon: 'close',
bgClassName: 'bg-destroy-80',
iconClassName: 'text-destroy-20 group-hover:text-destroy-10',
@ -72,7 +72,10 @@ export const UpdaterModal = ({
<ActionButton
Element="button"
onClick={() => onResolve({ wantUpdate: true })}
icon={{ icon: 'arrowRight', bgClassName: 'dark:bg-chalkboard-80' }}
iconStart={{
icon: 'arrowRight',
bgClassName: 'dark:bg-chalkboard-80',
}}
className="dark:hover:bg-chalkboard-80/50"
data-testid="update-button-update"
>

View File

@ -31,7 +31,7 @@ export const UpdaterRestartModal = ({
<ActionButton
Element="button"
onClick={() => onResolve({ wantRestart: false })}
icon={{
iconStart={{
icon: 'close',
bgClassName: 'bg-destroy-80',
iconClassName: 'text-destroy-20 group-hover:text-destroy-10',
@ -44,7 +44,10 @@ export const UpdaterRestartModal = ({
<ActionButton
Element="button"
onClick={() => onResolve({ wantRestart: true })}
icon={{ icon: 'arrowRight', bgClassName: 'dark:bg-chalkboard-80' }}
iconStart={{
icon: 'arrowRight',
bgClassName: 'dark:bg-chalkboard-80',
}}
className="dark:hover:bg-chalkboard-80/50"
data-testid="update-restrart-button-update"
>

View File

@ -55,7 +55,7 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
) : (
<ActionButton
Element={Popover.Button}
icon={{ icon: 'menu' }}
iconStart={{ icon: 'menu' }}
className="border-transparent !px-0"
data-testid="user-sidebar-toggle"
>
@ -120,7 +120,7 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
<div className="p-4 flex flex-col gap-2">
<ActionButton
Element="button"
icon={{ icon: 'settings' }}
iconStart={{ icon: 'settings' }}
className="border-transparent dark:border-transparent hover:bg-transparent"
onClick={() => {
// since /settings is a nested route the sidebar doesn't close
@ -138,7 +138,7 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
<ActionButton
Element="externalLink"
to="https://github.com/KittyCAD/modeling-app/discussions"
icon={{ icon: faGithub, className: 'p-1', size: 'sm' }}
iconStart={{ icon: faGithub, className: 'p-1', size: 'sm' }}
className="border-transparent dark:border-transparent"
>
Request a feature
@ -146,7 +146,7 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
<ActionButton
Element="externalLink"
to="https://github.com/KittyCAD/modeling-app/issues/new/choose"
icon={{ icon: faBug, className: 'p-1', size: 'sm' }}
iconStart={{ icon: faBug, className: 'p-1', size: 'sm' }}
className="border-transparent dark:border-transparent"
>
Report a bug
@ -154,7 +154,7 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
<ActionButton
Element="button"
onClick={() => send('Log out')}
icon={{
iconStart={{
icon: faSignOutAlt,
className: 'p-1',
bgClassName: '!bg-transparent',

View File

@ -24,7 +24,7 @@ export function WasmErrBanner() {
<ActionButton
Element="button"
onClick={() => setBannerDismissed(true)}
icon={{
iconStart={{
icon: 'close',
className: 'p-1',
bgClassName:

View File

@ -210,7 +210,7 @@ const Home = () => {
: '')
}
onClick={() => setSearchParams(getNextSearchParams(sort, 'name'))}
icon={{
iconStart={{
icon: getSortIcon(sort, 'name'),
className: 'p-1.5',
iconClassName: !sort.includes('name')
@ -232,7 +232,7 @@ const Home = () => {
onClick={() =>
setSearchParams(getNextSearchParams(sort, 'modified'))
}
icon={{
iconStart={{
icon: sort ? getSortIcon(sort, 'modified') : faArrowDown,
className: 'p-1.5',
iconClassName: !isSortByModified ? '!text-chalkboard-40' : '',
@ -278,7 +278,7 @@ const Home = () => {
<ActionButton
Element="button"
onClick={() => send('Create project')}
icon={{ icon: faPlus, iconClassName: 'p-1 w-4' }}
iconStart={{ icon: faPlus, iconClassName: 'p-1 w-4' }}
data-testid="home-new-file"
>
New project

View File

@ -51,7 +51,7 @@ export default function Units() {
<ActionButton
Element="button"
onClick={dismiss}
icon={{
iconStart={{
icon: faXmark,
bgClassName: 'bg-destroy-80',
iconClassName:
@ -64,7 +64,7 @@ export default function Units() {
<ActionButton
Element="button"
onClick={next}
icon={{ icon: faArrowRight }}
iconStart={{ icon: faArrowRight }}
>
Next: Camera
</ActionButton>

View File

@ -144,7 +144,7 @@ export function OnboardingButtons({
<ActionButton
Element="button"
onClick={dismiss}
icon={{
iconStart={{
icon: 'close',
bgClassName: 'bg-destroy-80',
iconClassName: 'text-destroy-20 group-hover:text-destroy-10',
@ -161,7 +161,7 @@ export function OnboardingButtons({
<ActionButton
Element="button"
onClick={next}
icon={{ icon: 'arrowRight', bgClassName: 'dark:bg-chalkboard-80' }}
iconStart={{ icon: 'arrowRight', bgClassName: 'dark:bg-chalkboard-80' }}
className="dark:hover:bg-chalkboard-80/50"
data-testid="onboarding-next"
>

View File

@ -269,7 +269,7 @@ export const Settings = () => {
<ActionButton
Element="button"
onClick={restartOnboarding}
icon={{
iconStart={{
icon: 'refresh',
size: 'sm',
className: 'p-1',
@ -300,7 +300,7 @@ export const Settings = () => {
)
showInFolder(paths[searchParamTab])
}}
icon={{
iconStart={{
icon: 'folder',
size: 'sm',
className: 'p-1',
@ -319,7 +319,7 @@ export const Settings = () => {
})
toast.success('Settings restored to default')
}}
icon={{
iconStart={{
icon: 'refresh',
size: 'sm',
className: 'p-1 text-chalkboard-10',

View File

@ -65,7 +65,7 @@ const SignIn = () => {
<ActionButton
Element="button"
onClick={signInTauri}
icon={{ icon: 'arrowRight' }}
iconStart={{ icon: 'arrowRight' }}
className="w-fit mt-4"
data-testid="sign-in-button"
>
@ -80,7 +80,7 @@ const SignIn = () => {
typeof window !== 'undefined' &&
window.location.href.replace('signin', '')
)}`}
icon={{ icon: 'arrowRight' }}
iconStart={{ icon: 'arrowRight' }}
className="w-fit mt-4"
>
Sign in