Toolbar rewrite: (mostly) fixed content, separate config, rich tooltips, and roadmapped tools (#3119)

* Basic implementation of rich tooltips

* Break out config to its own file, add a bunch of items

* Better lower right control tooltip sizing

* Add a bunch of sketch tools to the config

* Fix hotkey collisions and UX polish

* Get tests working again

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Re-run CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* We updated how the sidebar buttons' test IDs are generated, fix it post-merge

* fmt

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Re-run CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Re-run CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Re-run CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Frank Noirot
2024-07-24 23:33:31 -04:00
committed by GitHub
parent ea0a3ac3ba
commit c38e52fbb7
33 changed files with 1480 additions and 679 deletions

View File

@ -1,56 +1,93 @@
import { Popover } from '@headlessui/react'
import { ActionButton, ActionButtonProps } from './ActionButton'
import { ActionButtonProps } from './ActionButton'
import { CustomIcon } from './CustomIcon'
type ActionButtonSplitProps = Omit<ActionButtonProps, 'iconEnd'> & {
type ActionButtonSplitProps = ActionButtonProps & { Element: 'button' } & {
name?: string
splitMenuItems: {
id: string
label: string
shortcut?: string
onClick: () => void
disabled?: boolean
status?: 'available' | 'unavailable' | 'kcl-only'
}[]
}
export function ActionButtonDropdown({
splitMenuItems,
className,
children,
...props
}: ActionButtonSplitProps) {
const baseClassNames = `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`
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}
data-testid={item.label}
>
<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 className={`${baseClassNames} ${className}`}>
{({ close }) => (
<>
{children}
<Popover.Button className="border-transparent dark:border-transparent p-0 m-0 rounded-none !outline-none ui-open:border-primary ui-open:bg-primary">
<CustomIcon
name="caretDown"
className={
'w-3.5 h-5 text-chalkboard-70 dark:text-chalkboard-40 rounded-none ' +
'ui-open:rotate-180 ui-open:!text-chalkboard-10'
}
/>
<span className="sr-only">
{props.name ? props.name + ': ' : ''}open menu
</span>
</Popover.Button>
<Popover.Panel
as="ul"
className="!pointer-events-auto absolute z-20 left-1/2 -translate-x-1/2 top-full mt-4 w-fit max-w-[280px] max-h-[80vh] overflow-y-auto py-2 flex flex-col 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()
// Close the popover
close()
}}
className="group/button flex items-center gap-6 px-3 py-1 font-sans text-xs hover:bg-primary/10 dark:hover:bg-chalkboard-80 border-0 m-0 w-full rounded-none text-left disabled:!bg-transparent dark:disabled:text-chalkboard-60"
disabled={item.disabled}
data-testid={'dropdown-' + item.id}
>
<span className="capitalize flex-grow text-left">
{item.label}
</span>
{item.status === 'unavailable' ? (
<div className="flex flex-none items-center gap-1">
<span className="text-chalkboard-70 dark:text-chalkboard-40">
In development
</span>
<CustomIcon
name="lockClosed"
className="w-4 h-4 text-chalkboard-70 dark:text-chalkboard-40"
/>
</div>
) : item.status === 'kcl-only' ? (
<div className="flex flex-none items-center gap-1">
<span className="text-chalkboard-70 dark:text-chalkboard-40">
KCL code only
</span>
<CustomIcon
name="code"
className="w-4 h-4 text-chalkboard-70 dark:text-chalkboard-40"
/>
</div>
) : item.shortcut ? (
<kbd className="hotkey flex-none group-disabled/button:text-chalkboard-50 dark:group-disabled/button:text-chalkboard-70 group-disabled/button:border-chalkboard-20 dark:group-disabled/button:border-chalkboard-80">
{item.shortcut}
</kbd>
) : null}
</button>
</li>
))}
</Popover.Panel>
</>
)}
</Popover>
)
}